Merge "Identity Check API" into main
diff --git a/Android.bp b/Android.bp
index 8f7bd1b..087030b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -132,6 +132,7 @@
flags_packages: [
"aconfig_settings_flags",
"android.app.flags-aconfig",
+ "android.provider.flags-aconfig",
],
}
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 11d9779..cdd9535 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -5297,7 +5297,7 @@
android:name="Settings$ContactsStorageSettingsActivity"
android:label="@string/contacts_storage_settings_title"
android:exported="true"
- android:featureFlag="com.android.settings.flags.enable_contacts_default_account_in_settings">
+ android:featureFlag="android.provider.new_default_account_api_enabled">
<intent-filter>
<action android:name="android.provider.action.SET_DEFAULT_ACCOUNT" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/aconfig/catalyst/network_and_internet.aconfig b/aconfig/catalyst/network_and_internet.aconfig
index 130905f..e8943e6 100644
--- a/aconfig/catalyst/network_and_internet.aconfig
+++ b/aconfig/catalyst/network_and_internet.aconfig
@@ -35,3 +35,11 @@
description: "Flag for Wi-Fi calling screen"
bug: "323791114"
}
+
+flag {
+ name: "catalyst_restrict_background_parent_entry"
+ namespace: "android_settings"
+ description: "Flag for Data Saver"
+ bug: "323791114"
+}
+
diff --git a/aconfig/catalyst/system.aconfig b/aconfig/catalyst/system.aconfig
new file mode 100644
index 0000000..f87ff44
--- /dev/null
+++ b/aconfig/catalyst/system.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.settings.flags"
+container: "system"
+
+flag {
+ name: "catalyst_language_setting"
+ namespace: "android_settings"
+ description: "Flag for System -> Languages screen"
+ bug: "323791114"
+}
diff --git a/aconfig/settings_telephony_flag_declarations.aconfig b/aconfig/settings_telephony_flag_declarations.aconfig
index dab1b45..0279125 100644
--- a/aconfig/settings_telephony_flag_declarations.aconfig
+++ b/aconfig/settings_telephony_flag_declarations.aconfig
@@ -14,3 +14,19 @@
description: "Control the Dual SIM onobarding feature"
bug: "298898436"
}
+
+# OWNER=yomna TARGET=25Q2
+flag {
+ name: "mobile_network_security_2g"
+ namespace: "cellular_security"
+ description: "Exposing 2G toggles in Mobile Network Security page"
+ bug: "355062720"
+}
+
+# OWNER=yomna TARGET=25Q2
+flag {
+ name: "add_security_transparency_to_eng_menu"
+ namespace: "cellular_security"
+ description: "Exposing security transparency features to field engineering menu"
+ bug: "355062720"
+}
diff --git a/res/xml/language_settings.xml b/res/xml/language_settings.xml
index 4613cb0..7618399 100644
--- a/res/xml/language_settings.xml
+++ b/res/xml/language_settings.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/languages_settings"
- android:key="languages_settings">
+ android:key="language_settings">
<PreferenceCategory
android:key="languages_category"
android:title="@string/locale_picker_category_title">
diff --git a/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java b/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java
index 0550a9a..db239aa 100644
--- a/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java
+++ b/src/com/android/settings/applications/appcompat/UserAspectRatioManager.java
@@ -36,6 +36,7 @@
import android.app.AppGlobals;
import android.app.compat.CompatChanges;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
@@ -44,6 +45,7 @@
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.SparseIntArray;
import androidx.annotation.NonNull;
@@ -71,6 +73,7 @@
private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = true;
final boolean mIsUserMinAspectRatioAppDefaultFlagEnabled = Flags.userMinAspectRatioAppDefault();
+ private final boolean mIgnoreActivityOrientationRequest;
private final Context mContext;
private final IPackageManager mIPm;
@@ -90,6 +93,8 @@
mUserAspectRatioA11yMap = new ArrayMap<>();
mUserAspectRatioOrder = new SparseIntArray();
mUserAspectRatioMap = getUserMinAspectRatioMapping();
+ mIgnoreActivityOrientationRequest = getValueFromDeviceConfig(
+ "ignore_activity_orientation_request", false);
}
/**
@@ -113,6 +118,24 @@
? aspectRatio : USER_MIN_ASPECT_RATIO_UNSET;
}
+ // TODO b/374903057 reuse method from ActivityRecord
+ boolean isUniversalResizeable(@NonNull String packageName, int userId) {
+ try {
+ final ApplicationInfo info = mIPm.getApplicationInfo(
+ packageName, 0 /* flags */, userId);
+ if (info == null || info.category == ApplicationInfo.CATEGORY_GAME) {
+ return false;
+ }
+ final boolean compatEnabled = Flags.universalResizableByDefault()
+ && info.isChangeEnabled(ActivityInfo.UNIVERSAL_RESIZABLE_BY_DEFAULT);
+ return compatEnabled || mIgnoreActivityOrientationRequest;
+ } catch (RemoteException e) {
+ Log.e("UserAspectRatioManager", "Could not access application info for "
+ + packageName + ":\n" + e);
+ return false;
+ }
+ }
+
/**
* @return corresponding string for {@link PackageManager.UserMinAspectRatio} value
*/
@@ -127,7 +150,7 @@
return appDefault;
}
- return isCurrentSelectionFromManufacturerOverride(packageName, userId, aspectRatio)
+ return isUnsetAndRequiresFullscreenOverride(packageName, userId, aspectRatio)
? getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN, packageName, userId)
: mUserAspectRatioMap.getOrDefault(aspectRatio, appDefault);
}
@@ -139,7 +162,7 @@
public CharSequence getAccessibleEntry(@PackageManager.UserMinAspectRatio int aspectRatio,
@NonNull String packageName) {
final int userId = mContext.getUserId();
- return isCurrentSelectionFromManufacturerOverride(packageName, userId, aspectRatio)
+ return isUnsetAndRequiresFullscreenOverride(packageName, userId, aspectRatio)
? getAccessibleEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN, packageName)
: mUserAspectRatioA11yMap.getOrDefault(aspectRatio,
getUserMinAspectRatioEntry(aspectRatio, packageName, userId));
@@ -203,7 +226,7 @@
@PackageManager.UserMinAspectRatio int userOverride) {
return (userOverride != USER_MIN_ASPECT_RATIO_UNSET
&& userOverride != USER_MIN_ASPECT_RATIO_APP_DEFAULT)
- || isCurrentSelectionFromManufacturerOverride(app.packageName, getUserId(app.uid),
+ || isUnsetAndRequiresFullscreenOverride(app.packageName, getUserId(app.uid),
userOverride);
}
@@ -224,7 +247,7 @@
/**
* Whether the device manufacturer has overridden app's orientation to
* {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_USER} to force app to fullscreen
- * and app has not opted-out from the treatment
+ * or app is universal resizeable, and app has not opted-out from the treatment
*/
boolean isOverrideToFullscreenEnabled(String pkgName, int userId) {
Boolean appAllowsOrientationOverride = readComponentProperty(mContext.getPackageManager(),
@@ -232,7 +255,8 @@
return mIsUserMinAspectRatioAppDefaultFlagEnabled
&& hasAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN, pkgName)
&& !FALSE.equals(appAllowsOrientationOverride)
- && isFullscreenCompatChangeEnabled(pkgName, userId);
+ && (isFullscreenCompatChangeEnabled(pkgName, userId)
+ || isUniversalResizeable(pkgName, userId));
}
boolean isFullscreenCompatChangeEnabled(String pkgName, int userId) {
@@ -240,7 +264,11 @@
OVERRIDE_ANY_ORIENTATION_TO_USER, pkgName, UserHandle.of(userId));
}
- private boolean isCurrentSelectionFromManufacturerOverride(String pkgName, int userId,
+ /**
+ * Whether the aspect ratio is unset and we desire to interpret it as fullscreen rather than
+ * app default because of manufacturer override or because the app is universal resizeable
+ */
+ private boolean isUnsetAndRequiresFullscreenOverride(String pkgName, int userId,
@PackageManager.UserMinAspectRatio int aspectRatio) {
return aspectRatio == USER_MIN_ASPECT_RATIO_UNSET
&& isOverrideToFullscreenEnabled(pkgName, userId);
diff --git a/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java b/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java
index 6c179da..e4343e5 100644
--- a/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java
+++ b/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java
@@ -21,11 +21,11 @@
import android.content.Context;
import android.os.UserHandle;
import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
+import android.provider.Flags;
import android.util.Log;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
-import com.android.settings.flags.Flags;
import com.android.settingslib.accounts.AuthenticatorHelper;
/**
@@ -54,7 +54,7 @@
@Override
public int getAvailabilityStatus() {
- return (Flags.enableContactsDefaultAccountInSettings()
+ return (Flags.newDefaultAccountApiEnabled()
&& mCurrentDefaultAccountAndState != null) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@@ -71,7 +71,12 @@
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL) {
return mContext.getResources().getString(
R.string.contacts_storage_local_account_summary);
- } else if (currentDefaultAccount != null) {
+ } else if (currentDefaultAccountState
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_SIM) {
+ return mContext.getResources().getString(
+ R.string.sim_card_label);
+ } else if (currentDefaultAccountState
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD) {
String accountTypeLabel = (String) mAuthenticatorHelper.getLabelForType(mContext,
currentDefaultAccount.type);
// If there's no account type, or the account type is the same as the
diff --git a/src/com/android/settings/applications/contacts/ContactsStorageSettings.java b/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
index 3d449cf..8e71d08 100644
--- a/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
+++ b/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
@@ -28,7 +28,9 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
+import android.util.Log;
import android.widget.Toast;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -79,10 +81,16 @@
for (String preferenceKey : mAccountMap.keySet()) {
if (selectedPreferenceKey.equals(preferenceKey)) {
try {
+ DefaultAccountAndState currentDefaultAccount = mAccountMap.get(preferenceKey);
DefaultAccount.setDefaultAccountForNewContacts(getContentResolver(),
- mAccountMap.get(preferenceKey));
+ currentDefaultAccount);
selectedPref.setChecked(true);
+ if (currentDefaultAccount.getState()
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD) {
+ startMoveLocalAndSimContactsActivity();
+ }
} catch (RuntimeException e) {
+ Log.e(TAG, "Error setting the default account " + e);
Toast.makeText(getContext(),
R.string.contacts_storage_set_default_account_error_message,
Toast.LENGTH_SHORT).show();
@@ -123,9 +131,14 @@
// when creating eligible account preferences.
mAccountMap.clear();
final PreferenceScreen screen = getPreferenceScreen();
+ // If the default account is SIM, we should show in the page, otherwise don't show.
+ SelectorWithWidgetPreference simAccountPreference = buildSimAccountPreference();
+ if (simAccountPreference != null) {
+ getPreferenceScreen().addPreference(simAccountPreference);
+ }
List<Account> accounts = DefaultAccount.getEligibleCloudAccounts(getContentResolver());
for (int i = 0; i < accounts.size(); i++) {
- screen.addPreference(buildAccountPreference(accounts.get(i), /*order=*/i));
+ screen.addPreference(buildCloudAccountPreference(accounts.get(i), /*order=*/i));
}
// If there's no eligible account types, the "Add Account" preference should
// not be shown to the users.
@@ -156,7 +169,7 @@
if (mAccountMap.containsKey(preferenceKey)) {
preference = getPreferenceScreen().findPreference(preferenceKey);
} else if (preferenceKey != null && currentDefaultAccount != null) {
- preference = buildAccountPreference(currentDefaultAccount, mAccountMap.size());
+ preference = buildCloudAccountPreference(currentDefaultAccount, mAccountMap.size());
getPreferenceScreen().addPreference(preference);
}
if (preference != null) {
@@ -165,7 +178,7 @@
}
//TODO: Add preference category on account preferences.
- private SelectorWithWidgetPreference buildAccountPreference(Account account, int order) {
+ private SelectorWithWidgetPreference buildCloudAccountPreference(Account account, int order) {
SelectorWithWidgetPreference preference = new SelectorWithWidgetPreference(
getPrefContext());
DefaultAccountAndState accountAndState = DefaultAccountAndState.ofCloud(account);
@@ -180,6 +193,26 @@
return preference;
}
+ @Nullable
+ private SelectorWithWidgetPreference buildSimAccountPreference() {
+ DefaultAccountAndState currentDefaultAccountAndState =
+ DefaultAccount.getDefaultAccountForNewContacts(getContentResolver());
+ if (currentDefaultAccountAndState.getState()
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_SIM) {
+ String preferenceKey = getAccountHashCode(currentDefaultAccountAndState);
+ SelectorWithWidgetPreference preference = new SelectorWithWidgetPreference(
+ getPrefContext());
+ preference.setTitle(R.string.sim_card_label);
+ preference.setIcon(R.drawable.ic_sim_card);
+ preference.setSummary(R.string.sim_card_label);
+ preference.setKey(preferenceKey);
+ preference.setOnClickListener(this);
+ mAccountMap.put(preferenceKey, currentDefaultAccountAndState);
+ return preference;
+ }
+ return null;
+ }
+
private RestrictedPreference buildAddAccountPreference(boolean noAccountBeenAdded) {
RestrictedPreference preference = new RestrictedPreference(getPrefContext());
preference.setKey(PREF_KEY_ADD_ACCOUNT);
@@ -194,7 +227,17 @@
return preference;
}
- private @Nullable String getAccountHashCode(DefaultAccountAndState currentDefaultAccountAndState) {
+ private void startMoveLocalAndSimContactsActivity() {
+ Intent intent = new Intent()
+ .setAction(DefaultAccount.ACTION_MOVE_CONTACTS_TO_DEFAULT_ACCOUNT)
+ .setPackage("com.android.providers.contacts")
+ .addFlags(FLAG_ACTIVITY_NEW_TASK);
+ getContext().startActivity(intent);
+ }
+
+ @Nullable
+ private String getAccountHashCode(
+ DefaultAccountAndState currentDefaultAccountAndState) {
Account currentDefaultAccount = currentDefaultAccountAndState.getAccount();
if (currentDefaultAccount != null && (currentDefaultAccountAndState.getState()
== DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 0e51d17..2860ce8 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -421,11 +421,13 @@
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
List<String> invisibleProfiles = List.of();
if (Flags.enableBluetoothDeviceDetailsPolish()) {
- mFormatter =
- FeatureFactory.getFeatureFactory()
- .getBluetoothFeatureProvider()
- .getDeviceDetailsFragmentFormatter(
- requireContext(), this, mBluetoothAdapter, mCachedDevice);
+ if (mFormatter == null) {
+ mFormatter =
+ FeatureFactory.getFeatureFactory()
+ .getBluetoothFeatureProvider()
+ .getDeviceDetailsFragmentFormatter(
+ requireContext(), this, mBluetoothAdapter, mCachedDevice);
+ }
invisibleProfiles =
mFormatter.getInvisibleBluetoothProfiles(
FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
index be0f6f3..1bad5e5 100644
--- a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
@@ -25,7 +25,6 @@
import android.net.Uri;
import androidx.annotation.NonNull;
-import androidx.lifecycle.LifecycleCoroutineScope;
import androidx.preference.Preference;
import com.android.settings.SettingsPreferenceFragment;
@@ -34,12 +33,12 @@
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository;
+import kotlinx.coroutines.CoroutineScope;
+
import java.util.List;
import java.util.Set;
-/**
- * Provider for bluetooth related features.
- */
+/** Provider for bluetooth related features. */
public interface BluetoothFeatureProvider {
/**
@@ -86,26 +85,25 @@
/**
* Gets the bluetooth profile preference keys which should be hidden in the device details page.
*
- * @param context Context
+ * @param context Context
* @param bluetoothDevice the bluetooth device
* @return the profiles which should be hidden
*/
- Set<String> getInvisibleProfilePreferenceKeys(
- Context context, BluetoothDevice bluetoothDevice);
+ Set<String> getInvisibleProfilePreferenceKeys(Context context, BluetoothDevice bluetoothDevice);
/** Gets DeviceSettingRepository. */
@NonNull
DeviceSettingRepository getDeviceSettingRepository(
@NonNull Context context,
@NonNull BluetoothAdapter bluetoothAdapter,
- @NonNull LifecycleCoroutineScope scope);
+ @NonNull CoroutineScope scope);
/** Gets spatial audio interactor. */
@NonNull
SpatialAudioInteractor getSpatialAudioInteractor(
@NonNull Context context,
@NonNull AudioManager audioManager,
- @NonNull LifecycleCoroutineScope scope);
+ @NonNull CoroutineScope scope);
/** Gets device details fragment layout formatter. */
@NonNull
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt
index 25c586e..6f967a2 100644
--- a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt
@@ -22,6 +22,7 @@
import android.media.AudioManager
import android.media.Spatializer
import android.net.Uri
+import android.util.Log
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.preference.Preference
import com.android.settings.SettingsPreferenceFragment
@@ -37,6 +38,7 @@
import com.android.settingslib.media.domain.interactor.SpatializerInteractor
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableSet
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
/** Impl of [BluetoothFeatureProvider] */
@@ -76,14 +78,14 @@
override fun getDeviceSettingRepository(
context: Context,
bluetoothAdapter: BluetoothAdapter,
- scope: LifecycleCoroutineScope
+ scope: CoroutineScope
): DeviceSettingRepository =
DeviceSettingRepositoryImpl(context, bluetoothAdapter, scope, Dispatchers.IO)
override fun getSpatialAudioInteractor(
context: Context,
audioManager: AudioManager,
- scope: LifecycleCoroutineScope
+ scope: CoroutineScope,
): SpatialAudioInteractor {
return SpatialAudioInteractorImpl(
context, audioManager,
diff --git a/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractor.kt b/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractor.kt
index 6b72b53..4b91716a 100644
--- a/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractor.kt
+++ b/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractor.kt
@@ -147,7 +147,7 @@
}
companion object {
- private const val TAG = "SpatialAudioInteractorImpl"
+ private const val TAG = "SpatialAudioInteractor"
private const val INDEX_SPATIAL_AUDIO_OFF = 0
private const val INDEX_SPATIAL_AUDIO_ON = 1
private const val INDEX_HEAD_TRACKING_ENABLED = 2
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
index ad4176f..13c3b50 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
@@ -19,11 +19,10 @@
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
-import android.media.AudioManager
import android.os.Bundle
import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.shrinkVertically
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
@@ -33,14 +32,12 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import com.android.settings.R
import com.android.settings.SettingsPreferenceFragment
@@ -52,7 +49,6 @@
import com.android.settings.bluetooth.ui.view.DeviceDetailsMoreSettingsFragment.Companion.KEY_DEVICE_ADDRESS
import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
import com.android.settings.core.SubSettingLauncher
-import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settings.spa.preference.ComposePreference
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
@@ -97,29 +93,17 @@
class DeviceDetailsFragmentFormatterImpl(
private val context: Context,
private val fragment: SettingsPreferenceFragment,
- bluetoothAdapter: BluetoothAdapter,
+ private val bluetoothAdapter: BluetoothAdapter,
private val cachedDevice: CachedBluetoothDevice,
private val backgroundCoroutineContext: CoroutineContext,
) : DeviceDetailsFragmentFormatter {
- private val repository =
- featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
- fragment.requireActivity().application,
- bluetoothAdapter,
- fragment.lifecycleScope,
- )
- private val spatialAudioInteractor =
- featureFactory.bluetoothFeatureProvider.getSpatialAudioInteractor(
- fragment.requireActivity().application,
- context.getSystemService(AudioManager::class.java),
- fragment.lifecycleScope,
- )
+
private val viewModel: BluetoothDeviceDetailsViewModel =
ViewModelProvider(
fragment,
BluetoothDeviceDetailsViewModel.Factory(
fragment.requireActivity().application,
- repository,
- spatialAudioInteractor,
+ bluetoothAdapter,
cachedDevice,
backgroundCoroutineContext,
),
@@ -224,8 +208,8 @@
val settings = contents
AnimatedVisibility(
visible = settings.isNotEmpty(),
- enter = expandVertically(expandFrom = Alignment.Top),
- exit = shrinkVertically(shrinkTowards = Alignment.Top),
+ enter = fadeIn(),
+ exit = fadeOut(),
) {
Box {
Box(
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
index 7cb1c0d..66fba70 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
@@ -120,13 +120,15 @@
finish()
return emptyList()
}
- formatter =
- featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(
- requireContext(),
- this,
- bluetoothManager.adapter,
- cachedDevice,
- )
+ if (!this::formatter.isInitialized) {
+ formatter =
+ featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(
+ requireContext(),
+ this,
+ bluetoothManager.adapter,
+ cachedDevice,
+ )
+ }
helpItem =
formatter
.getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
diff --git a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
index 3b7a582..1ea2da3 100644
--- a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
+++ b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
@@ -17,20 +17,22 @@
package com.android.settings.bluetooth.ui.viewmodel
import android.app.Application
+import android.bluetooth.BluetoothAdapter
+import android.media.AudioManager
+import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.android.settings.R
-import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutColumn
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
+import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
-import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
@@ -47,12 +49,24 @@
class BluetoothDeviceDetailsViewModel(
private val application: Application,
- private val deviceSettingRepository: DeviceSettingRepository,
- private val spatialAudioInteractor: SpatialAudioInteractor,
+ private val bluetoothAdapter: BluetoothAdapter,
private val cachedDevice: CachedBluetoothDevice,
backgroundCoroutineContext: CoroutineContext,
) : AndroidViewModel(application) {
+ private val deviceSettingRepository =
+ featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
+ application,
+ bluetoothAdapter,
+ viewModelScope,
+ )
+ private val spatialAudioInteractor =
+ featureFactory.bluetoothFeatureProvider.getSpatialAudioInteractor(
+ application,
+ application.getSystemService(AudioManager::class.java),
+ viewModelScope,
+ )
+
private val items =
viewModelScope.async(backgroundCoroutineContext, start = CoroutineStart.LAZY) {
deviceSettingRepository.getDeviceSettingsConfig(cachedDevice)
@@ -202,8 +216,7 @@
class Factory(
private val application: Application,
- private val deviceSettingRepository: DeviceSettingRepository,
- private val spatialAudioInteractor: SpatialAudioInteractor,
+ private val bluetoothAdapter: BluetoothAdapter,
private val cachedDevice: CachedBluetoothDevice,
private val backgroundCoroutineContext: CoroutineContext,
) : ViewModelProvider.Factory {
@@ -211,8 +224,7 @@
@Suppress("UNCHECKED_CAST")
return BluetoothDeviceDetailsViewModel(
application,
- deviceSettingRepository,
- spatialAudioInteractor,
+ bluetoothAdapter,
cachedDevice,
backgroundCoroutineContext,
)
diff --git a/src/com/android/settings/datausage/DataSaverScreen.kt b/src/com/android/settings/datausage/DataSaverScreen.kt
new file mode 100644
index 0000000..171f002
--- /dev/null
+++ b/src/com/android/settings/datausage/DataSaverScreen.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.datausage
+
+import android.content.Context
+import com.android.settings.R
+import com.android.settings.flags.Flags
+import com.android.settingslib.metadata.ProvidePreferenceScreen
+import com.android.settingslib.metadata.preferenceHierarchy
+import com.android.settingslib.preference.PreferenceScreenCreator
+
+@ProvidePreferenceScreen
+class DataSaverScreen : PreferenceScreenCreator {
+ override val key
+ get() = KEY
+
+ override val title
+ get() = R.string.data_saver_title
+
+ override val icon: Int
+ get() = R.drawable.ic_settings_data_usage
+
+ override fun order(context: Context) = 10
+
+ override fun isFlagEnabled(context: Context) = Flags.catalystRestrictBackgroundParentEntry()
+
+ override fun fragmentClass() = DataSaverSummary::class.java
+
+ override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
+
+ override fun hasCompleteHierarchy() = false
+
+ companion object {
+ const val KEY = "restrict_background_parent_entry"
+ }
+}
diff --git a/src/com/android/settings/datausage/DataSaverSummary.kt b/src/com/android/settings/datausage/DataSaverSummary.kt
index e118bd6..8db6333 100644
--- a/src/com/android/settings/datausage/DataSaverSummary.kt
+++ b/src/com/android/settings/datausage/DataSaverSummary.kt
@@ -79,6 +79,8 @@
override fun getHelpResource() = R.string.help_url_data_saver
override fun getLogTag() = TAG
+ override fun getPreferenceScreenBindingKey(context: Context) = DataSaverScreen.KEY
+
private val dataSaverBackendListener = object : DataSaverBackend.Listener {
override fun onDataSaverChanged(isDataSaving: Boolean) {
synchronized(this) {
diff --git a/src/com/android/settings/language/LanguageSettingScreen.kt b/src/com/android/settings/language/LanguageSettingScreen.kt
new file mode 100644
index 0000000..09ca11b
--- /dev/null
+++ b/src/com/android/settings/language/LanguageSettingScreen.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.language
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import com.android.settings.R
+import com.android.settings.Settings.LanguageSettingsActivity
+import com.android.settings.flags.Flags
+import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.ProvidePreferenceScreen
+import com.android.settingslib.metadata.preferenceHierarchy
+import com.android.settingslib.preference.PreferenceScreenCreator
+
+@ProvidePreferenceScreen
+class LanguageSettingScreen: PreferenceScreenCreator {
+ override val key: String
+ get() = KEY
+
+ override val title: Int
+ get() = R.string.languages_settings
+
+ override val summary: Int
+ get() = R.string.languages_setting_summary
+
+ override val icon: Int
+ get() = R.drawable.ic_settings_languages
+
+ override fun isFlagEnabled(context: Context) = Flags.catalystLanguageSetting()
+
+ override fun hasCompleteHierarchy() = false
+
+ override fun fragmentClass() = LanguageSettings::class.java
+
+ override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
+
+ companion object {
+ const val KEY = "language_setting"
+ }
+}
diff --git a/src/com/android/settings/language/LanguageSettings.java b/src/com/android/settings/language/LanguageSettings.java
index a5adb02..d992ff2 100644
--- a/src/com/android/settings/language/LanguageSettings.java
+++ b/src/com/android/settings/language/LanguageSettings.java
@@ -67,6 +67,11 @@
}
@Override
+ public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
+ return LanguageSettingScreen.KEY;
+ }
+
+ @Override
protected int getPreferenceScreenResId() {
return R.xml.language_settings;
}
diff --git a/src/com/android/settings/network/SimOnboardingService.kt b/src/com/android/settings/network/SimOnboardingService.kt
index e4f17e2..0882b81 100644
--- a/src/com/android/settings/network/SimOnboardingService.kt
+++ b/src/com/android/settings/network/SimOnboardingService.kt
@@ -74,8 +74,11 @@
}
var isEsimProfileEnabled: Boolean = false
get() {
- activeSubInfoList.stream().anyMatch { it.isEmbedded }
- return false
+ return activeSubInfoList.stream().anyMatch { it.isEmbedded }
+ }
+ var isRemovableSimProfileEnabled: Boolean = false
+ get() {
+ return activeSubInfoList.stream().anyMatch { !it.isEmbedded }
}
var doesTargetSimActive = false
get() {
@@ -288,8 +291,8 @@
Log.d(TAG, "Hardware does not support DSDS.")
return false
}
- val isActiveSim = activeSubInfoList.isNotEmpty()
- if (isMultipleEnabledProfilesSupported && isActiveSim) {
+ val anyActiveSim = activeSubInfoList.isNotEmpty()
+ if (isMultipleEnabledProfilesSupported && anyActiveSim) {
Log.d(TAG,
"Device supports MEP and eSIM operation and eSIM profile is enabled."
+ " DSDS condition satisfied."
@@ -297,15 +300,13 @@
return true
}
- if (doesTargetSimHaveEsimOperation) {
- if (UiccSlotRepository(telephonyManager).anyRemovablePhysicalSimEnabled()) {
- Log.d(
- TAG,
- "eSIM operation and removable PSIM is enabled. DSDS condition satisfied."
- )
- return true
- }
- } else if (isEsimProfileEnabled) {
+ if (doesTargetSimHaveEsimOperation && isRemovableSimProfileEnabled) {
+ Log.d(TAG,
+ "eSIM operation and removable PSIM is enabled. DSDS condition satisfied."
+ )
+ return true
+ }
+ if (!doesTargetSimHaveEsimOperation && isEsimProfileEnabled) {
Log.d(TAG,
"Removable SIM operation and eSIM profile is enabled. DSDS condition"
+ " satisfied."
diff --git a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
index f9751f1..f4d2ce2 100644
--- a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
+++ b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
@@ -557,15 +557,17 @@
Log.d(TAG, "Hardware does not support DSDS.");
return false;
}
- boolean isActiveSim = SubscriptionUtil.getActiveSubscriptions(
+ boolean anyActiveSim = SubscriptionUtil.getActiveSubscriptions(
mSubscriptionManager).size() > 0;
- if (isMultipleEnabledProfilesSupported() && isActiveSim) {
+ if (isMultipleEnabledProfilesSupported() && anyActiveSim) {
Log.d(TAG,
"Device supports MEP and eSIM operation and eSIM profile is enabled."
+ " DSDS condition satisfied.");
return true;
}
- boolean isRemovableSimEnabled = isRemovableSimEnabled();
+ boolean isRemovableSimEnabled =
+ SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager).stream()
+ .anyMatch(subInfo-> !subInfo.isEmbedded());
if (mIsEsimOperation && isRemovableSimEnabled) {
Log.d(TAG, "eSIM operation and removable SIM is enabled. DSDS condition satisfied.");
return true;
@@ -583,7 +585,7 @@
}
private boolean isRemovableSimEnabled() {
- return new UiccSlotRepository(mTelMgr).anyRemovablePhysicalSimEnabled();
+ return new UiccSlotRepository(mTelMgr).anyRemovablePhysicalSimSlotActiveAndInserted();
}
private boolean isMultipleEnabledProfilesSupported() {
diff --git a/src/com/android/settings/network/telephony/UiccSlotRepository.kt b/src/com/android/settings/network/telephony/UiccSlotRepository.kt
index 3a83805..8a20329 100644
--- a/src/com/android/settings/network/telephony/UiccSlotRepository.kt
+++ b/src/com/android/settings/network/telephony/UiccSlotRepository.kt
@@ -22,17 +22,17 @@
class UiccSlotRepository(private val telephonyManager: TelephonyManager?) {
- /** Returns whether any removable physical sim is enabled. */
- fun anyRemovablePhysicalSimEnabled(): Boolean {
+ /** Returns whether any removable physical sim slot is active and the sim is inserted. */
+ fun anyRemovablePhysicalSimSlotActiveAndInserted(): Boolean {
val result =
telephonyManager?.uiccSlotsInfo?.any { uiccSlotInfo: UiccSlotInfo? ->
- uiccSlotInfo.isRemovablePhysicalSimEnabled()
+ uiccSlotInfo.isRemovablePhysicalSimSlotActiveAndInserted()
} ?: false
Log.i(TAG, "anyRemovablePhysicalSimEnabled: $result")
return result
}
- private fun UiccSlotInfo?.isRemovablePhysicalSimEnabled(): Boolean {
+ private fun UiccSlotInfo?.isRemovablePhysicalSimSlotActiveAndInserted(): Boolean {
return this != null &&
isRemovable &&
!isEuicc &&
diff --git a/src/com/android/settings/network/tether/TetherSettings.java b/src/com/android/settings/network/tether/TetherSettings.java
index 77ef4b6..7458514 100644
--- a/src/com/android/settings/network/tether/TetherSettings.java
+++ b/src/com/android/settings/network/tether/TetherSettings.java
@@ -54,8 +54,8 @@
import androidx.preference.TwoStatePreference;
import com.android.settings.R;
-import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.Utils;
+import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.datausage.DataSaverBackend;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.wifi.tether.WifiTetherPreferenceController;
@@ -75,7 +75,7 @@
* Displays preferences for Tethering.
*/
@SearchIndexable
-public class TetherSettings extends RestrictedSettingsFragment
+public class TetherSettings extends RestrictedDashboardFragment
implements DataSaverBackend.Listener {
@VisibleForTesting
@@ -144,10 +144,18 @@
}
@Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.tether_prefs;
+ }
+
+ @Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- // Even when the UI is restricted, addPreferencesFromResource cannot be omitted.
- addPreferencesFromResource(R.xml.tether_prefs);
setIfOnlyAvailableForAdmins(true);
if (isUiRestricted()) {
return;
diff --git a/src/com/android/settings/notification/app/BundleListPreferenceController.java b/src/com/android/settings/notification/app/BundleListPreferenceController.java
index 82e910c..9ada049 100644
--- a/src/com/android/settings/notification/app/BundleListPreferenceController.java
+++ b/src/com/android/settings/notification/app/BundleListPreferenceController.java
@@ -91,14 +91,27 @@
public void updateState(Preference preference) {
PreferenceCategory category = (PreferenceCategory) preference;
- createOrUpdatePrefForChannel(category,
- mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID));
- createOrUpdatePrefForChannel(category,
- mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID));
- createOrUpdatePrefForChannel(category,
- mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID));
- createOrUpdatePrefForChannel(category,
- mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID));
+ NotificationChannel promos = mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID);
+ if (promos != null) {
+ createOrUpdatePrefForChannel(category, promos);
+ }
+ NotificationChannel recs = mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID);
+ if (recs != null) {
+ createOrUpdatePrefForChannel(category, recs);
+ }
+ NotificationChannel social = mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID);
+ if (social != null) {
+ createOrUpdatePrefForChannel(category, social);
+ }
+ NotificationChannel news = mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID);
+ if (news != null) {
+ createOrUpdatePrefForChannel(category, news);
+ }
+
+ int preferenceCount = ((PreferenceGroup) preference).getPreferenceCount();
+ if (preferenceCount == 0) {
+ preference.setVisible(false);
+ }
}
@NonNull
@@ -167,5 +180,4 @@
icon.setTintList(Utils.getColorAccent(mContext));
return icon;
}
-
}
diff --git a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
index 014a190..13d5c6e 100644
--- a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
@@ -40,6 +40,7 @@
import androidx.preference.Preference;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
@@ -108,7 +109,9 @@
tryParseScheduleConditionId(mode.getRule().getConditionId());
if (schedule != null) {
preference.setTitle(SystemZenRules.getTimeSummary(mContext, schedule));
- preference.setSummary(SystemZenRules.getShortDaysSummary(mContext, schedule));
+ preference.setSummary(Utils.createAccessibleSequence(
+ SystemZenRules.getDaysOfWeekShort(mContext, schedule),
+ SystemZenRules.getDaysOfWeekFull(mContext, schedule)));
} else {
// Fallback, but shouldn't happen.
Log.wtf(TAG, "SCHEDULE_TIME mode without schedule: " + mode);
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
index 9febba3..5ea9b3c 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java
@@ -58,6 +58,9 @@
private final WifiManager mWifiManager;
@VisibleForTesting
+ boolean mIsSwitchBusy;
+
+ @VisibleForTesting
DataSaverBackend mDataSaverBackend;
@VisibleForTesting
final ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback =
@@ -102,8 +105,8 @@
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- // Filter out unnecessary callbacks when switch is disabled.
- if (!buttonView.isEnabled()) return;
+ // Filter out inappropriate callbacks when switch is busy.
+ if (mIsSwitchBusy) return;
if (isChecked) {
startTether();
@@ -115,14 +118,14 @@
void stopTether() {
if (!isWifiApActivated()) return;
- mSwitchBar.setEnabled(false);
+ mIsSwitchBusy = true;
mConnectivityManager.stopTethering(TETHERING_WIFI);
}
void startTether() {
if (isWifiApActivated()) return;
- mSwitchBar.setEnabled(false);
+ mIsSwitchBusy = true;
mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
}
@@ -159,6 +162,7 @@
private void updateWifiSwitch() {
mSwitchBar.setEnabled(!mDataSaverBackend.isDataSaverEnabled());
+ mIsSwitchBusy = false;
}
@Override
diff --git a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java
index f55cbb4..f954b22 100644
--- a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java
@@ -43,9 +43,9 @@
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.ContactsContract;
import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
+import android.provider.Flags;
import com.android.settings.R;
-import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAuthenticationHelper;
import org.junit.Before;
@@ -108,20 +108,20 @@
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_CONTACTS_DEFAULT_ACCOUNT_IN_SETTINGS)
+ @EnableFlags(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
public void getAvailabilityStatus_flagIsOn_shouldReturnAvailable() {
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_CONTACTS_DEFAULT_ACCOUNT_IN_SETTINGS)
+ @RequiresFlagsDisabled(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
public void getAvailabilityStatus_flagIsOff_shouldReturnConditionallyUnavailable() {
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
CONDITIONALLY_UNAVAILABLE);
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_CONTACTS_DEFAULT_ACCOUNT_IN_SETTINGS)
+ @EnableFlags(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
public void getAvailabilityStatus_illegalStateExceptionThrown_shouldReturnConditionallyUnavailable()
throws Exception {
when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
@@ -135,7 +135,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_CONTACTS_DEFAULT_ACCOUNT_IN_SETTINGS)
+ @EnableFlags(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
public void getAvailabilityStatus_runtimeExceptionThrown_shouldReturnConditionallyUnavailable()
throws Exception {
when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
@@ -179,6 +179,24 @@
}
@Test
+ public void getSummary_simAccountIsSetAsDefault_shouldReturnSimAccountSummary()
+ throws Exception {
+ Bundle bundle = new Bundle();
+ bundle.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_SIM);
+ bundle.putString(Settings.ACCOUNT_TYPE, "SIM");
+ bundle.putString(Settings.ACCOUNT_NAME, "SIM");
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(bundle);
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getString(eq(R.string.sim_card_label))).thenReturn("SIM");
+ mPreferenceController = new ContactsStoragePreferenceController(mContext,
+ CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
+
+ assertThat(mPreferenceController.getSummary()).isEqualTo("SIM");
+ }
+
+ @Test
public void getSummary_googleAccountIsSetAsDefault_shouldReturnGoogleAccountTypeAndAccountName()
throws Exception {
Bundle bundle = new Bundle();
diff --git a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
index a8c86e1..4e873fb 100644
--- a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
@@ -32,7 +32,6 @@
import static org.mockito.Mockito.when;
import android.accounts.Account;
-import android.accounts.AccountManager;
import android.app.settings.SettingsEnums;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -83,6 +82,8 @@
private static final Account TEST_ACCOUNT3 = new Account("test@outlook.com", "type3");
+ private static final Account SIM_ACCOUNT = new Account("SIM", "SIM");
+
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Spy
@@ -216,7 +217,9 @@
throws Exception {
Bundle currentDefaultAccount = new Bundle();
currentDefaultAccount.putInt(KEY_DEFAULT_ACCOUNT_STATE,
- DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL);
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD);
+ currentDefaultAccount.putString(ContactsContract.Settings.ACCOUNT_NAME, TEST_ACCOUNT2.name);
+ currentDefaultAccount.putString(ContactsContract.Settings.ACCOUNT_TYPE, TEST_ACCOUNT2.type);
when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
any())).thenReturn(currentDefaultAccount);
Bundle eligibleAccountBundle = new Bundle();
@@ -253,6 +256,14 @@
"test@samsung.com");
assertThat(setAccountBundle.getString(ContactsContract.Settings.ACCOUNT_TYPE)).isEqualTo(
"type2");
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).startActivity(intentCaptor.capture());
+ Intent moveContactsIntent = intentCaptor.getValue();
+ assertThat(moveContactsIntent.getAction()).isEqualTo(
+ ContactsContract.RawContacts.DefaultAccount.ACTION_MOVE_CONTACTS_TO_DEFAULT_ACCOUNT);
+ assertThat(moveContactsIntent.getPackage()).isEqualTo(
+ "com.android.providers.contacts");
}
@Test
@@ -299,6 +310,32 @@
}
@Test
+ public void verifyAccountPreference_defaultAccountIsSimAccount_createSimAccountPreference()
+ throws Exception {
+ Bundle currentDefaultAccount = new Bundle();
+ currentDefaultAccount.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_SIM);
+ currentDefaultAccount.putString(ContactsContract.Settings.ACCOUNT_NAME, SIM_ACCOUNT.name);
+ currentDefaultAccount.putString(ContactsContract.Settings.ACCOUNT_TYPE, SIM_ACCOUNT.type);
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(currentDefaultAccount);
+ Bundle eligibleAccountBundle = new Bundle();
+ eligibleAccountBundle.putParcelableArrayList(KEY_ELIGIBLE_DEFAULT_ACCOUNTS,
+ new ArrayList<>());
+ when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(),
+ any())).thenReturn(eligibleAccountBundle);
+
+ mContactsStorageSettings.refreshUI();
+
+ SelectorWithWidgetPreference simPreference = mScreen.findPreference(
+ String.valueOf(SIM_ACCOUNT.hashCode()));
+ assertThat(simPreference.getTitle()).isEqualTo("SIM");
+ assertThat(simPreference.getSummary()).isEqualTo("SIM");
+ assertThat(simPreference.getIcon()).isNotNull();
+ assertThat(simPreference.isChecked()).isTrue();
+ }
+
+ @Test
public void searchIndexProvider_shouldIndexResource() {
final List<SearchIndexableResource> indexRes =
ContactsStorageSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt b/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
index c3f938c..6813d94 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
@@ -19,6 +19,7 @@
import android.app.Application
import android.bluetooth.BluetoothAdapter
import android.graphics.Bitmap
+import android.media.AudioManager
import androidx.test.core.app.ApplicationProvider
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
@@ -46,7 +47,9 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
+import org.mockito.Mockito.any
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
@@ -76,11 +79,21 @@
val application = ApplicationProvider.getApplicationContext<Application>()
featureFactory = FakeFeatureFactory.setupForTest()
+ `when`(
+ featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
+ eq(application), eq(bluetoothAdapter), any()
+ ))
+ .thenReturn(repository)
+ `when`(
+ featureFactory.bluetoothFeatureProvider.getSpatialAudioInteractor(
+ eq(application), any(AudioManager::class.java), any()
+ ))
+ .thenReturn(spatialAudioInteractor)
+
underTest =
BluetoothDeviceDetailsViewModel(
application,
- repository,
- spatialAudioInteractor,
+ bluetoothAdapter,
cachedDevice,
testScope.testScheduler)
}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataSaverScreenTest.kt b/tests/robotests/src/com/android/settings/datausage/DataSaverScreenTest.kt
new file mode 100644
index 0000000..08af4c0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/datausage/DataSaverScreenTest.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.datausage
+
+import com.android.settings.flags.Flags
+import com.android.settingslib.preference.CatalystScreenTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class DataSaverScreenTest : CatalystScreenTestCase() {
+ override val preferenceScreenCreator = DataSaverScreen()
+ override val flagName
+ get() = Flags.FLAG_CATALYST_RESTRICT_BACKGROUND_PARENT_ENTRY
+
+ override fun migration() {}
+
+ @Test
+ fun key() {
+ assertThat(preferenceScreenCreator.key).isEqualTo(DataSaverScreen.KEY)
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java b/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java
index 4e0fb03..8c537e0 100644
--- a/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java
@@ -54,7 +54,7 @@
import androidx.preference.SwitchPreference;
import com.android.settings.R;
-import com.android.settings.RestrictedSettingsFragment;
+import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.wifi.tether.WifiTetherPreferenceController;
import com.android.settingslib.RestrictedSwitchPreference;
@@ -130,14 +130,12 @@
}
@Test
- @Config(shadows = ShadowRestrictedSettingsFragment.class)
+ @Config(shadows = ShadowRestrictedDashboardFragment.class)
public void onCreate_isUiRestricted_doNotSetupViewModel() {
- doNothing().when(mTetherSettings).addPreferencesFromResource(anyInt());
when(mTetherSettings.isUiRestricted()).thenReturn(true);
mTetherSettings.onCreate(null);
- verify(mTetherSettings).addPreferencesFromResource(anyInt());
verify(mTetherSettings, never()).setupViewModel();
}
@@ -454,8 +452,8 @@
}
}
- @Implements(RestrictedSettingsFragment.class)
- public static final class ShadowRestrictedSettingsFragment {
+ @Implements(RestrictedDashboardFragment.class)
+ public static final class ShadowRestrictedDashboardFragment {
@Implementation
public void onCreate(Bundle icicle) {
// do nothing
diff --git a/tests/robotests/src/com/android/settings/notification/app/BundleListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BundleListPreferenceControllerTest.java
index 8b8c77e..a8de8ef 100644
--- a/tests/robotests/src/com/android/settings/notification/app/BundleListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/BundleListPreferenceControllerTest.java
@@ -89,15 +89,6 @@
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
mGroupList = new PreferenceCategory(mContext);
mPreferenceScreen.addPreference(mGroupList);
-
- when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID)).thenReturn(
- new NotificationChannel(PROMOTIONS_ID, PROMOTIONS_ID, 2));
- when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID)).thenReturn(
- new NotificationChannel(NEWS_ID, NEWS_ID, 2));
- when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID)).thenReturn(
- new NotificationChannel(SOCIAL_MEDIA_ID, SOCIAL_MEDIA_ID, 2));
- when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID)).thenReturn(
- new NotificationChannel(RECS_ID, RECS_ID, 2));
}
@Test
@@ -132,6 +123,14 @@
@Test
public void updateState() {
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID)).thenReturn(
+ new NotificationChannel(PROMOTIONS_ID, PROMOTIONS_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID)).thenReturn(
+ new NotificationChannel(NEWS_ID, NEWS_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID)).thenReturn(
+ new NotificationChannel(SOCIAL_MEDIA_ID, SOCIAL_MEDIA_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID)).thenReturn(
+ new NotificationChannel(RECS_ID, RECS_ID, 2));
mController.updateState(mGroupList);
assertThat(mGroupList.getPreferenceCount()).isEqualTo(4);
assertThat(mGroupList.findPreference(PROMOTIONS_ID).getTitle()).isEqualTo(PROMOTIONS_ID);
@@ -142,19 +141,38 @@
}
@Test
- public void updateState_updateChildren() {
+ public void updateState_noBundles() {
mController.updateState(mGroupList);
- assertThat(mGroupList.getPreferenceCount()).isEqualTo(4);
+ assertThat(mGroupList.getPreferenceCount()).isEqualTo(0);
+ assertThat(mGroupList.isVisible()).isFalse();
+ }
+ @Test
+ public void updateState_onlySomeBundlesUsed() {
when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID)).thenReturn(
new NotificationChannel(PROMOTIONS_ID, PROMOTIONS_ID, 2));
+ mController.updateState(mGroupList);
+ assertThat(mGroupList.getPreferenceCount()).isEqualTo(1);
+ assertThat(mGroupList.findPreference(PROMOTIONS_ID).getTitle()).isEqualTo(PROMOTIONS_ID);
+ }
+
+ @Test
+ public void updateState_noDuplicateChannelsOnReload() {
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID)).thenReturn(
+ new NotificationChannel(PROMOTIONS_ID, PROMOTIONS_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID)).thenReturn(
+ new NotificationChannel(NEWS_ID, NEWS_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID)).thenReturn(
+ new NotificationChannel(SOCIAL_MEDIA_ID, SOCIAL_MEDIA_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID)).thenReturn(
+ new NotificationChannel(RECS_ID, RECS_ID, 2));
mController.updateState(mGroupList);
assertThat(mGroupList.getPreferenceCount()).isEqualTo(4);
+ mController.updateState(mGroupList);
+ assertThat(mGroupList.getPreferenceCount()).isEqualTo(4);
assertThat(((PrimarySwitchPreference) mGroupList.findPreference(NEWS_ID)).isChecked())
.isEqualTo(false);
- assertThat(((PrimarySwitchPreference) mGroupList.findPreference(NEWS_ID)).isChecked())
- .isEqualTo(false);
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
index b7af71b..d916dcf 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
@@ -44,6 +44,8 @@
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
+import android.text.Spanned;
+import android.text.style.TtsSpan;
import android.widget.TextView;
import androidx.preference.PreferenceManager;
@@ -293,7 +295,14 @@
assertThat(mPreference.isVisible()).isTrue();
assertThat(mPreference.getTitle()).isEqualTo("1:00 AM - 3:00 PM");
- assertThat(mPreference.getSummary()).isEqualTo("Mon - Tue, Thu");
+ Spanned summary = (Spanned) mPreference.getSummary();
+ assertThat(summary.toString()).isEqualTo("Mon - Tue, Thu");
+ TtsSpan[] ttsSpans = summary.getSpans(0, summary.length(), TtsSpan.class);
+ assertThat(ttsSpans).hasLength(1);
+ assertThat(ttsSpans[0].getType()).isEqualTo(TtsSpan.TYPE_TEXT);
+ assertThat(ttsSpans[0].getArgs().getString(TtsSpan.ARG_TEXT)).isEqualTo(
+ "Monday to Tuesday, Thursday");
+
// Destination as written into the intent by SubSettingLauncher
assertThat(
mPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
index 0982f26..32e3a61 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSwitchBarControllerTest.java
@@ -147,8 +147,8 @@
}
@Test
- public void onSwitchChanged_switchNotEnabled_doNothingForTethering() {
- when(mSwitch.isEnabled()).thenReturn(false);
+ public void onSwitchChanged_switchIsBusy_doNothingForTethering() {
+ mController.mIsSwitchBusy = true;
mController.onCheckedChanged(mSwitch, true);
diff --git a/tests/spa_unit/src/com/android/settings/network/SimOnboardingServiceTest.kt b/tests/spa_unit/src/com/android/settings/network/SimOnboardingServiceTest.kt
index 6f9029e..676ac48 100644
--- a/tests/spa_unit/src/com/android/settings/network/SimOnboardingServiceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/SimOnboardingServiceTest.kt
@@ -16,21 +16,55 @@
package com.android.settings.network
+import android.content.Context
import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import android.telephony.UiccCardInfo
+import android.telephony.UiccPortInfo
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
-import org.junit.Rule
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+
@RunWith(AndroidJUnit4::class)
class SimOnboardingServiceTest {
+ val simOnboardingService = SimOnboardingService()
+
+ private val mockTelephonyManager = mock<TelephonyManager> {
+ on { activeModemCount } doReturn 2
+ on { isMultiSimSupported } doReturn TelephonyManager.MULTISIM_ALLOWED
+ on { uiccCardsInfo } doReturn mepUiccCardInfoList
+ }
+
+ private val mockSubscriptionManager = mock<SubscriptionManager> {
+ on { activeSubscriptionInfoList } doReturn listOf(
+ SUB_INFO_1,
+ SUB_INFO_2
+ )
+ on { availableSubscriptionInfoList } doReturn listOf(
+ SUB_INFO_1,
+ SUB_INFO_2,
+ SUB_INFO_3,
+ )
+ }
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager
+ on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+ }
@Test
fun addItemForRenaming_addItemWithNewName_findItem() {
- val simOnboardingService = SimOnboardingService()
val newName = "NewName"
-
simOnboardingService.addItemForRenaming(SUB_INFO_1, newName)
assertThat(simOnboardingService.renameMutableMap)
@@ -39,8 +73,6 @@
@Test
fun addItemForRenaming_sameNameAndItemNotInList_removeItem() {
- val simOnboardingService = SimOnboardingService()
-
simOnboardingService.addItemForRenaming(SUB_INFO_1, DISPLAY_NAME_1)
assertThat(simOnboardingService.renameMutableMap)
@@ -49,7 +81,6 @@
@Test
fun addItemForRenaming_sameNameAndItemInList_removeItem() {
- val simOnboardingService = SimOnboardingService()
simOnboardingService.renameMutableMap[SUB_INFO_1.subscriptionId] = "NewName"
simOnboardingService.addItemForRenaming(SUB_INFO_1, DISPLAY_NAME_1)
@@ -58,13 +89,205 @@
.doesNotContainKey(SUB_INFO_1.subscriptionId)
}
+ @Test
+ fun isDsdsConditionSatisfied_isMultiSimEnabled_returnFalse(){
+ simOnboardingService.initData(SUB_ID_3, context, {})
+
+ assertThat(simOnboardingService.isDsdsConditionSatisfied()).isFalse()
+ }
+
+ @Test
+ fun isDsdsConditionSatisfied_isNotMultiSimSupported_returnFalse() {
+ mockTelephonyManager.stub {
+ on { activeModemCount } doReturn 1
+ on {
+ isMultiSimSupported
+ } doReturn TelephonyManager.MULTISIM_NOT_SUPPORTED_BY_HARDWARE
+ }
+ simOnboardingService.initData(SUB_ID_3, context, {})
+
+ assertThat(simOnboardingService.isDsdsConditionSatisfied()).isFalse()
+ }
+
+ @Test
+ fun isDsdsConditionSatisfied_mepAndOneActiveSim_returnTrue() = runBlocking {
+ mockTelephonyManager.stub {
+ on { activeModemCount } doReturn 1
+ }
+ simOnboardingService.initData(SUB_ID_3, context, {})
+ delay(100)
+
+ assertThat(simOnboardingService.isDsdsConditionSatisfied()).isTrue()
+ }
+
+ @Test
+ fun isDsdsConditionSatisfied_mepAndNoActiveSim_returnFalse() = runBlocking {
+ mockTelephonyManager.stub {
+ on { activeModemCount } doReturn 1
+ }
+ mockSubscriptionManager.stub {
+ on { activeSubscriptionInfoList } doReturn listOf()
+ }
+ simOnboardingService.initData(SUB_ID_3, context, {})
+ delay(100)
+
+ assertThat(simOnboardingService.isDsdsConditionSatisfied()).isFalse()
+ }
+
+ @Test
+ fun isDsdsConditionSatisfied_insertEsimAndOneActivePsimNoMep_returnTrue() = runBlocking {
+ mockTelephonyManager.stub {
+ on { getActiveModemCount() } doReturn 1
+ on { uiccCardsInfo } doReturn noMepUiccCardInfoList
+ }
+ simOnboardingService.initData(SUB_ID_3, context, {})
+ delay(100)
+
+ assertThat(simOnboardingService.isDsdsConditionSatisfied()).isTrue()
+ }
+
+ @Test
+ fun isDsdsConditionSatisfied_insertEsimAndNoPsimNoMep_returnFalse() = runBlocking {
+ mockTelephonyManager.stub {
+ on { getActiveModemCount() } doReturn 1
+ on { uiccCardsInfo } doReturn noMepUiccCardInfoList
+ }
+ mockSubscriptionManager.stub {
+ on { activeSubscriptionInfoList } doReturn listOf()
+ }
+ simOnboardingService.initData(SUB_ID_3, context, {})
+ delay(100)
+
+ assertThat(simOnboardingService.isDsdsConditionSatisfied()).isFalse()
+ }
+
+ @Test
+ fun isDsdsConditionSatisfied_insertPsimAndOneActiveEsimNoMep_returnTrue() = runBlocking {
+ mockTelephonyManager.stub {
+ on { getActiveModemCount() } doReturn 1
+ on { uiccCardsInfo } doReturn noMepUiccCardInfoList
+ }
+ mockSubscriptionManager.stub {
+ on { activeSubscriptionInfoList } doReturn listOf(
+ SUB_INFO_2
+ )
+ }
+ simOnboardingService.initData(SUB_ID_1, context, {})
+ delay(100)
+
+ assertThat(simOnboardingService.isDsdsConditionSatisfied()).isTrue()
+ }
+
+ @Test
+ fun isDsdsConditionSatisfied_insertPsimAndNoEsimNoMep_returnFalse() = runBlocking {
+ mockTelephonyManager.stub {
+ on { getActiveModemCount() } doReturn 1
+ on { uiccCardsInfo } doReturn noMepUiccCardInfoList
+ }
+ mockSubscriptionManager.stub {
+ on { activeSubscriptionInfoList } doReturn listOf()
+ }
+ simOnboardingService.initData(SUB_ID_1, context, {})
+ delay(100)
+
+ assertThat(simOnboardingService.isDsdsConditionSatisfied()).isFalse()
+ }
+
private companion object {
const val SUB_ID_1 = 1
+ const val SUB_ID_2 = 2
+ const val SUB_ID_3 = 3
+ const val SUB_ID_4 = 4
const val DISPLAY_NAME_1 = "Sub 1"
val SUB_INFO_1: SubscriptionInfo = SubscriptionInfo.Builder().apply {
setId(SUB_ID_1)
setDisplayName(DISPLAY_NAME_1)
}.build()
+
+ val SUB_INFO_2: SubscriptionInfo = SubscriptionInfo.Builder().apply {
+ setId(SUB_ID_2)
+ setEmbedded(true)
+ }.build()
+
+ val SUB_INFO_3: SubscriptionInfo = SubscriptionInfo.Builder().apply {
+ setId(SUB_ID_3)
+ setEmbedded(true)
+ }.build()
+
+ val SUB_INFO_4: SubscriptionInfo = SubscriptionInfo.Builder().apply {
+ setId(SUB_ID_4)
+ }.build()
+
+ private const val REMOVABLE_CARD_ID_1: Int = 25
+ private const val REMOVABLE_CARD_ID_2: Int = 26
+ private const val EUICC_CARD_ID_3: Int = 27
+ private const val EUICC_CARD_ID_4: Int = 28
+
+ val noMepUiccCardInfoList: List<UiccCardInfo> = listOf(
+ createUiccCardInfo(
+ isEuicc = true,
+ cardId = EUICC_CARD_ID_3,
+ physicalSlotIndex = 0,
+ isRemovable = false,
+ isMultipleEnabledProfileSupported = false,
+ logicalSlotIndex = -1,
+ portIndex = -1
+ ),
+ createUiccCardInfo(
+ isEuicc = false,
+ cardId = REMOVABLE_CARD_ID_1,
+ physicalSlotIndex = 1,
+ isRemovable = true,
+ isMultipleEnabledProfileSupported = false,
+ logicalSlotIndex = -1,
+ portIndex = -1
+ )
+ )
+ val mepUiccCardInfoList: List<UiccCardInfo> = listOf(
+ createUiccCardInfo(
+ isEuicc = true,
+ cardId = EUICC_CARD_ID_3,
+ physicalSlotIndex = 0,
+ isRemovable = false,
+ logicalSlotIndex = -1,
+ portIndex = -1
+ ),
+ createUiccCardInfo(
+ isEuicc = false,
+ cardId = REMOVABLE_CARD_ID_1,
+ physicalSlotIndex = 1,
+ isRemovable = true,
+ logicalSlotIndex = -1,
+ portIndex = -1
+ )
+ )
+
+ private fun createUiccCardInfo(
+ isEuicc: Boolean,
+ cardId: Int,
+ physicalSlotIndex: Int,
+ isRemovable: Boolean,
+ logicalSlotIndex: Int,
+ portIndex: Int,
+ isMultipleEnabledProfileSupported:Boolean = true,
+ ): UiccCardInfo {
+ return UiccCardInfo(
+ isEuicc, /* isEuicc */
+ cardId, /* cardId */
+ null, /* eid */
+ physicalSlotIndex, /* physicalSlotIndex */
+ isRemovable, /* isRemovable */
+ isMultipleEnabledProfileSupported, /* isMultipleEnabledProfileSupported */
+ listOf(
+ UiccPortInfo(
+ "123451234567890", /* iccId */
+ portIndex, /* portIdx */
+ logicalSlotIndex, /* logicalSlotIdx */
+ true /* isActive */
+ )
+ )
+ )
+ }
}
}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/UiccSlotRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/UiccSlotRepositoryTest.kt
index 96aa151..911e1d1 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/UiccSlotRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/UiccSlotRepositoryTest.kt
@@ -44,7 +44,7 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isFalse()
}
@@ -61,7 +61,7 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isFalse()
}
@@ -78,7 +78,7 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isTrue()
}
@@ -95,7 +95,7 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isTrue()
}
@@ -116,7 +116,7 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isFalse()
}
@@ -137,13 +137,13 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isTrue()
}
@Test
- fun anyRemovablePhysicalSimEnabled_activePsim_returnsTrue() {
+ fun anyRemovablePhysicalSimSlotActiveAndInserted_activePsim_returnsTrue() {
mockTelephonyManager.stub {
on { uiccSlotsInfo } doReturn
arrayOf(
@@ -152,13 +152,13 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isTrue()
}
@Test
- fun anyRemovablePhysicalSimEnabled_inactivePsim_returnsFalse() {
+ fun anyRemovablePhysicalSimSlotActiveAndInserted_inactivePsim_returnsFalse() {
mockTelephonyManager.stub {
on { uiccSlotsInfo } doReturn
arrayOf(
@@ -167,13 +167,13 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isFalse()
}
@Test
- fun anyRemovablePhysicalSimEnabled_activeEsimAndActivePsim_returnsTrue() {
+ fun anyRemovablePhysicalSimSlotActiveAndInserted_activeEsimAndActivePsim_returnsTrue() {
mockTelephonyManager.stub {
on { uiccSlotsInfo } doReturn
arrayOf(
@@ -184,13 +184,13 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isTrue()
}
@Test
- fun anyRemovablePhysicalSimEnabled_activeEsimAndInactivePsim_returnsFalse() {
+ fun anyRemovablePhysicalSimSlotActiveAndInserted_activeEsimAndInactivePsim_returnsFalse() {
mockTelephonyManager.stub {
on { uiccSlotsInfo } doReturn
arrayOf(
@@ -201,16 +201,16 @@
)
}
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isFalse()
}
@Test
- fun anyRemovablePhysicalSimEnabled_uiccSlotInfoIsNull_returnsFalse() {
+ fun anyRemovablePhysicalSimSlotActiveAndInserted_uiccSlotInfoIsNull_returnsFalse() {
mockTelephonyManager.stub { on { uiccSlotsInfo } doReturn arrayOf(null) }
- val result = repository.anyRemovablePhysicalSimEnabled()
+ val result = repository.anyRemovablePhysicalSimSlotActiveAndInserted()
assertThat(result).isFalse()
}
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index be43f8e..07df3c8 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -26,11 +26,14 @@
"androidx.test.ext.junit",
"androidx.test.rules",
"flag-junit",
+ "kotlin-test",
+ "mockito-kotlin2",
"mockito-target-minus-junit4",
"platform-test-annotations",
"platform-test-rules",
"truth",
"kotlinx_coroutines_test",
+ "SettingsLibPreference-testutils",
"Settings-testutils2",
"servicestests-utils",
// Don't add SettingsLib libraries here - you can use them directly as they are in the
diff --git a/tests/unit/src/com/android/settings/applications/appcompat/UserAspectRatioManagerTest.java b/tests/unit/src/com/android/settings/applications/appcompat/UserAspectRatioManagerTest.java
index 342212a..4c07555 100644
--- a/tests/unit/src/com/android/settings/applications/appcompat/UserAspectRatioManagerTest.java
+++ b/tests/unit/src/com/android/settings/applications/appcompat/UserAspectRatioManagerTest.java
@@ -331,9 +331,7 @@
.isEqualTo(getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_UNSET, mPackageName));
}
- @Test
- public void testGetUserMinAspectRatioEntry_enabledFullscreenOverride_returnsFullscreen() {
- setIsOverrideToFullscreenEnabled(true);
+ private void assertUnsetIsFullscreen() {
// Fullscreen option is pre-selected
assertThat(getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_UNSET, mPackageName))
.isEqualTo(ResourcesUtils.getResourcesString(
@@ -347,9 +345,7 @@
"user_aspect_ratio_app_default"));
}
- @Test
- public void testGetUserMinAspectRatioEntry_disabledFullscreenOverride_returnsUnchanged() {
- setIsOverrideToFullscreenEnabled(false);
+ private void assertUnsetIsAppDefault() {
// Fullscreen option is not pre-selected
assertThat(getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_UNSET, mPackageName))
.isEqualTo(ResourcesUtils.getResourcesString(
@@ -358,9 +354,43 @@
}
@Test
- public void testIsOverrideToFullscreenEnabled_returnsTrue()
+ public void testGetUserMinAspectRatioEntry_enabledFullscreenCompatChange_returnsFullscreen() {
+ setIsOverrideToFullscreenEnabledBecauseCompatChange(true);
+ assertUnsetIsFullscreen();
+ }
+
+ @Test
+ public void testGetUserMinAspectRatioEntry_enabledFullscreenOverrideUniRes_returnsFullscreen() {
+ setIsOverrideToFullscreenEnabledBecauseUniversalResizeable(true);
+ assertUnsetIsFullscreen();
+ }
+
+ @Test
+ public void testGetUserMinAspectRatioEntry_noFullscreenCompatChange_returnsUnchanged() {
+ setIsOverrideToFullscreenEnabledBecauseCompatChange(false);
+ assertUnsetIsAppDefault();
+ }
+
+ @Test
+ public void testGetUserMinAspectRatioEntry_noFullscreenUnivRes_returnsUnchanged() {
+ setIsOverrideToFullscreenEnabledBecauseUniversalResizeable(false);
+ assertUnsetIsAppDefault();
+ }
+
+ @Test
+ public void testIsOverrideToFullscreenEnabledCompatChange_returnsTrue()
throws PackageManager.NameNotFoundException {
- setIsOverrideToFullscreenEnabled(true);
+ setIsOverrideToFullscreenEnabledBecauseCompatChange(true);
+ assertTrue(mUtils.isOverrideToFullscreenEnabled(mPackageName, mContext.getUserId()));
+
+ mockProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, true);
+ assertTrue(mUtils.isOverrideToFullscreenEnabled(mPackageName, mContext.getUserId()));
+ }
+
+ @Test
+ public void testIsOverrideToFullscreenEnabledUnivRes_returnsTrue()
+ throws PackageManager.NameNotFoundException {
+ setIsOverrideToFullscreenEnabledBecauseUniversalResizeable(true);
assertTrue(mUtils.isOverrideToFullscreenEnabled(mPackageName, mContext.getUserId()));
mockProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, true);
@@ -370,7 +400,7 @@
@Test
public void testIsOverrideToFullscreenEnabled_optOut_returnsFalse()
throws PackageManager.NameNotFoundException {
- setIsOverrideToFullscreenEnabled(true);
+ setIsOverrideToFullscreenEnabledBecauseCompatChange(true);
mockProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, false);
assertFalse(mUtils.isOverrideToFullscreenEnabled(mPackageName, mContext.getUserId()));
}
@@ -382,6 +412,12 @@
}
@Test
+ public void testIsOverrideToFullscreenEnabledUnivRes_flagDisabled_returnsFalse() {
+ mUtils.setFullscreenCompatChange(true);
+ assertFalse(mUtils.isOverrideToFullscreenEnabled(mPackageName, mContext.getUserId()));
+ }
+
+ @Test
public void testIsOverrideToFullscreenEnabled_optionDisabled_returnsFalse() {
mUtils.setFullscreenCompatChange(true);
when(mUtils.hasAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN, mPackageName))
@@ -389,7 +425,7 @@
assertFalse(mUtils.isOverrideToFullscreenEnabled(mPackageName, mContext.getUserId()));
}
- private void setIsOverrideToFullscreenEnabled(boolean enabled) {
+ private void setIsOverrideToFullscreenEnabledBecauseCompatChange(boolean enabled) {
if (enabled) {
mSetFlagsRule.enableFlags(FLAG_USER_MIN_ASPECT_RATIO_APP_DEFAULT);
mUtils = new FakeUserAspectRatioManager(mContext, mIPm);
@@ -399,6 +435,16 @@
.thenReturn(enabled);
}
+ private void setIsOverrideToFullscreenEnabledBecauseUniversalResizeable(boolean enabled) {
+ if (enabled) {
+ mSetFlagsRule.enableFlags(FLAG_USER_MIN_ASPECT_RATIO_APP_DEFAULT);
+ mUtils = new FakeUserAspectRatioManager(mContext, mIPm);
+ }
+ mUtils.setUniversalResizeable(enabled);
+ when(mUtils.hasAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN, mPackageName))
+ .thenReturn(enabled);
+ }
+
private void enableAllDefaultAspectRatioOptions() {
final int[] aspectRatioOptions = new int[] {
USER_MIN_ASPECT_RATIO_UNSET,
@@ -457,6 +503,7 @@
private static class FakeUserAspectRatioManager extends UserAspectRatioManager {
private boolean mFullscreenCompatChange = false;
+ private boolean mIsUniversalResizeable = false;
private FakeUserAspectRatioManager(@NonNull Context context, IPackageManager pm) {
super(context, pm);
@@ -467,8 +514,17 @@
return mFullscreenCompatChange;
}
+ @Override
+ boolean isUniversalResizeable(String pkgName, int userId) {
+ return mIsUniversalResizeable;
+ }
+
void setFullscreenCompatChange(boolean enabled) {
mFullscreenCompatChange = enabled;
}
+
+ void setUniversalResizeable(boolean enabled) {
+ mIsUniversalResizeable = enabled;
+ }
}
}
diff --git a/tests/unit/src/com/android/settings/language/LanguageSettingScreenTest.kt b/tests/unit/src/com/android/settings/language/LanguageSettingScreenTest.kt
new file mode 100644
index 0000000..7b519a2
--- /dev/null
+++ b/tests/unit/src/com/android/settings/language/LanguageSettingScreenTest.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.language
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import com.android.settings.Settings.LanguageSettingsActivity
+import com.android.settings.flags.Flags
+import com.android.settingslib.preference.CatalystScreenTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert
+import org.junit.Test
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+
+class LanguageSettingScreenTest: CatalystScreenTestCase() {
+ override val preferenceScreenCreator = LanguageSettingScreen()
+
+ override val flagName: String
+ get() = Flags.FLAG_CATALYST_LANGUAGE_SETTING
+
+ @Test
+ fun key() {
+ assertThat(preferenceScreenCreator.key).isEqualTo(LanguageSettingScreen.KEY)
+ }
+
+ override fun migration() {}
+}