Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/aconfig/settings_flag_declarations.aconfig b/aconfig/settings_flag_declarations.aconfig
new file mode 100644
index 0000000..c4c33b0
--- /dev/null
+++ b/aconfig/settings_flag_declarations.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.settings.flags"
+
+flag {
+ name: "show_factory_reset_cancel_button"
+ namespace: "android_settings"
+ description: "This flag controls whether to show a Cancel button when factory reset"
+ bug: "300634367"
+}
diff --git a/res/layout/content_protection_preference_fragment.xml b/res/layout/content_protection_preference_fragment.xml
index a412d86..4c7352e 100644
--- a/res/layout/content_protection_preference_fragment.xml
+++ b/res/layout/content_protection_preference_fragment.xml
@@ -36,10 +36,11 @@
settings:lottie_rawRes="@drawable/content_protection_preference_illustration"
settings:searchable="false" />
- <SwitchPreference
+ <com.android.settingslib.RestrictedSwitchPreference
android:key="content_protection_preference_user_consent_work_profile_switch"
android:title="@string/content_protection_preference_user_consent_work_profile_switch_title"
- settings:isPreferenceVisible="false" />
+ settings:restrictedSwitchSummary="@string/summary_placeholder"
+ settings:controller="com.android.settings.security.ContentProtectionWorkSwitchController"/>
<com.android.settingslib.widget.FooterPreference
android:key="content_protection_preference_subpage_footer"
diff --git a/res/layout/fingerprint_v2_enroll_introduction.xml b/res/layout/fingerprint_v2_enroll_introduction.xml
index 2fd1f9c..cf39206 100644
--- a/res/layout/fingerprint_v2_enroll_introduction.xml
+++ b/res/layout/fingerprint_v2_enroll_introduction.xml
@@ -24,6 +24,7 @@
<LinearLayout
style="@style/SudContentFrame"
+ android:id="@+id/enroll_intro_content_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6524c20..55269e5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1301,7 +1301,20 @@
<!-- Title for Private Space account login error screen. [CHAR LIMIT=60] -->
<string name="privatespace_retry_signin_title">Sign in to set up Private Space</string>
<!-- Summary for the Private Space account login error screen. [CHAR LIMIT=NONE] -->
- <string name="privatespace_retry_summary">You need to sign in to a Account to set up Private Space</string>
+ <string name="privatespace_retry_summary">You need to sign in to an account to set up Private Space</string>
+
+ <!-- TODO(b/309950257): Remove below strings once QSTIle fulfillment is complete. -->
+ <!-- Header in hide Private Space settings page to unhide Private Space. [CHAR LIMIT=60] -->
+ <string name="privatespace_unhide_header">To show Private Space (Not final UX)</string>
+ <!-- Text in hide Private Space settings page on how to open Private Space setting. [CHAR LIMIT=NONE] -->
+ <string name="privatespace_open_settings">Open the Settings App</string>
+ <!-- Text in hide Private Space settings page on how to open Private Space setting. [CHAR LIMIT=NONE] -->
+ <string name="privatespace_tap_settings">Tap on Security & privacy > Private Space > Hide Private Space when locked</string>
+ <!-- Text in hide Private Space settings page to off hide toggle. [CHAR LIMIT=60] -->
+ <string name="privatespace_turnoff_hide">Turn off \‘Hide Private Space when locked\’ toggle</string>
+ <!-- Note in hide Private Space settings page to inform that this is a development feature. [CHAR LIMIT=NONE] -->
+ <string name="privatespace_development_note">Note to Googlers: The development of this feature is still in progress</string>
+
<!-- Text shown when "Add fingerprint" button is disabled -->
<string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
diff --git a/res/xml/privatespace_hide_locked.xml b/res/xml/privatespace_hide_locked.xml
index 60a814b..f26d207 100644
--- a/res/xml/privatespace_hide_locked.xml
+++ b/res/xml/privatespace_hide_locked.xml
@@ -21,7 +21,7 @@
<com.android.settingslib.widget.IllustrationPreference
android:key="privatespace_hide_video"
settings:searchable="false"
- settings:lottie_rawRes="@raw/lottie_privatespace_hide_placeholder"/>
+ settings:lottie_rawRes="@drawable/privatespace_placeholder_image"/>
<com.android.settingslib.widget.MainSwitchPreference
android:key="hide_when_locked"
@@ -34,27 +34,33 @@
android:selectable="false"
settings:searchable="false" />
+ <Preference
+ android:key="private_space_note"
+ android:summary="@string/privatespace_development_note"
+ android:selectable="false"
+ settings:searchable="false" />
+
<PreferenceCategory
- android:title="@string/privatespace_access_header">
+ android:title="@string/privatespace_unhide_header">
<Preference
android:key="search_when_locked_footer"
android:icon="@drawable/counter_1_24dp"
- android:title="@string/privatespace_search_description"
+ android:title="@string/privatespace_open_settings"
android:selectable="false"
settings:searchable="false" />
<Preference
android:key="tap_tile_footer"
android:icon="@drawable/counter_2_24dp"
- android:title="@string/privatespace_tap_tile_description"
+ android:title="@string/privatespace_tap_settings"
android:selectable="false"
settings:searchable="false" />
<Preference
- android:key="unlock_profile_footer"
+ android:key="turn_off_footer"
android:icon="@drawable/counter_3_24dp"
- android:title="@string/privatespace_unlock_description"
+ android:title="@string/privatespace_turnoff_hide"
android:selectable="false"
settings:searchable="false" />
diff --git a/src/com/android/settings/MainClear.java b/src/com/android/settings/MainClear.java
index 58fc0d5..0aba5ca 100644
--- a/src/com/android/settings/MainClear.java
+++ b/src/com/android/settings/MainClear.java
@@ -63,6 +63,7 @@
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
+import com.android.settings.flags.Flags;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.ConfirmLockPattern;
@@ -431,14 +432,24 @@
final GlifLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ final Activity activity = getActivity();
mixin.setPrimaryButton(
- new FooterButton.Builder(getActivity())
+ new FooterButton.Builder(activity)
.setText(R.string.main_clear_button_text)
.setListener(mInitiateListener)
.setButtonType(ButtonType.OTHER)
.setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
- .build()
- );
+ .build());
+ if (Flags.showFactoryResetCancelButton()) {
+ mixin.setSecondaryButton(
+ new FooterButton.Builder(activity)
+ .setText(android.R.string.cancel)
+ .setListener(view -> activity.onBackPressed())
+ .setButtonType(ButtonType.CANCEL)
+ .setTheme(
+ com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
+ .build());
+ }
mInitiateButton = mixin.getPrimaryButton();
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 594cf7a..308b3d5 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -1399,12 +1399,14 @@
super.onBindViewHolder(view);
mView = view.itemView;
mDeleteView = view.itemView.findViewById(R.id.delete_button);
- mDeleteView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mOnDeleteClickListener != null) {
- mOnDeleteClickListener.onDeleteClick(FingerprintPreference.this);
- }
+ if (mFingerprint != null) {
+ mDeleteView.setContentDescription(
+ mDeleteView.getContentDescription()
+ + " " + mFingerprint.getName().toString());
+ }
+ mDeleteView.setOnClickListener(v -> {
+ if (mOnDeleteClickListener != null) {
+ mOnDeleteClickListener.onDeleteClick(FingerprintPreference.this);
}
});
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
index b1ab301..32d201d 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/fragment/FingerprintEnrollIntroV2Fragment.kt
@@ -186,6 +186,9 @@
return view
}
+ /**
+ * TODO (b/305269201): This link isn't displaying for screenshot tests.
+ */
private fun setFooterLink(view: View) {
val footerLink: TextView = view.requireViewById(R.id.footer_learn_more)
footerLink.movementMethod = LinkMovementMethod.getInstance()
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
index 6b50b70..561a51a 100644
--- a/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectDialog.java
@@ -25,7 +25,9 @@
import android.content.DialogInterface.OnShowListener;
import android.content.Intent;
import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
import android.os.Bundle;
+import android.os.Flags;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -183,7 +185,10 @@
final UserManager userManager = UserManager.get(context);
for (int i = userHandles.size() - 1; i >= 0; i--) {
UserInfo userInfo = userManager.getUserInfo(userHandles.get(i).getIdentifier());
- if (userInfo == null || userInfo.isCloneProfile()) {
+ if (userInfo == null
+ || userInfo.isCloneProfile()
+ || (Flags.allowPrivateProfile()
+ && shouldHideUserInQuietMode(userHandles.get(i), userManager))) {
if (DEBUG) {
Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier());
}
@@ -214,7 +219,10 @@
final UserManager userManager = UserManager.get(context);
for (UserHandle userHandle : List.copyOf(tile.pendingIntentMap.keySet())) {
UserInfo userInfo = userManager.getUserInfo(userHandle.getIdentifier());
- if (userInfo == null || userInfo.isCloneProfile()) {
+ if (userInfo == null
+ || userInfo.isCloneProfile()
+ || (Flags.allowPrivateProfile()
+ && shouldHideUserInQuietMode(userHandle, userManager))) {
if (DEBUG) {
Log.d(TAG, "Delete the user: " + userHandle.getIdentifier());
}
@@ -223,4 +231,11 @@
}
}
}
+
+ private static boolean shouldHideUserInQuietMode(
+ UserHandle userHandle, UserManager userManager) {
+ UserProperties userProperties = userManager.getUserProperties(userHandle);
+ return userProperties.getHideInSettingsInQuietMode()
+ && userManager.isQuietModeEnabled(userHandle);
+ }
}
diff --git a/src/com/android/settings/dashboard/profileselector/UserAdapter.java b/src/com/android/settings/dashboard/profileselector/UserAdapter.java
index 0552a81..66ba815 100644
--- a/src/com/android/settings/dashboard/profileselector/UserAdapter.java
+++ b/src/com/android/settings/dashboard/profileselector/UserAdapter.java
@@ -17,7 +17,6 @@
package com.android.settings.dashboard.profileselector;
import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
@@ -51,11 +50,13 @@
/** Holder for user details */
public static class UserDetails {
private final UserHandle mUserHandle;
+ private final UserManager mUserManager;
private final Drawable mIcon;
private final String mTitle;
public UserDetails(UserHandle userHandle, UserManager um, Context context) {
mUserHandle = userHandle;
+ mUserManager = um;
UserInfo userInfo = um.getUserInfo(mUserHandle.getIdentifier());
int tintColor = Utils.getColorAttrDefaultColor(context,
com.android.internal.R.attr.materialColorPrimaryContainer);
@@ -73,16 +74,13 @@
DevicePolicyManager devicePolicyManager =
Objects.requireNonNull(context.getSystemService(DevicePolicyManager.class));
DevicePolicyResourcesManager resources = devicePolicyManager.getResources();
- int userHandle = mUserHandle.getIdentifier();
- if (userHandle == UserHandle.USER_CURRENT
- || userHandle == ActivityManager.getCurrentUser()) {
+ int userId = mUserHandle.getIdentifier();
+ if (userId == UserHandle.USER_CURRENT || userId == ActivityManager.getCurrentUser()) {
return resources.getString(PERSONAL_CATEGORY_HEADER,
() -> context.getString(
com.android.settingslib.R.string.category_personal));
- } else {
- return resources.getString(WORK_CATEGORY_HEADER,
- () -> context.getString(com.android.settingslib.R.string.category_work));
}
+ return (String) mUserManager.getBadgedLabelForUser(/* label= */ "", mUserHandle);
}
}
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.kt b/src/com/android/settings/datausage/BillingCyclePreference.kt
index 619f7e9..a6904bc 100644
--- a/src/com/android/settings/datausage/BillingCyclePreference.kt
+++ b/src/com/android/settings/datausage/BillingCyclePreference.kt
@@ -16,15 +16,21 @@
import android.app.settings.SettingsEnums
import android.content.Context
-import android.content.Intent
import android.net.NetworkTemplate
import android.os.Bundle
import android.util.AttributeSet
-import androidx.preference.Preference
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R
import com.android.settings.core.SubSettingLauncher
import com.android.settings.datausage.lib.BillingCycleRepository
-import com.android.settings.network.MobileDataEnabledListener
+import com.android.settings.network.mobileDataEnabledFlow
+import com.android.settings.spa.preference.ComposePreference
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import kotlinx.coroutines.flow.map
/**
* Preference which displays billing cycle of subscription
@@ -36,45 +42,31 @@
context: Context,
attrs: AttributeSet?,
private val repository: BillingCycleRepository = BillingCycleRepository(context),
-) : Preference(context, attrs), TemplatePreference {
- private lateinit var template: NetworkTemplate
- private var subId = 0
-
- private val listener = MobileDataEnabledListener(context) {
- updateEnabled()
- }
+) : ComposePreference(context, attrs), TemplatePreference {
override fun setTemplate(template: NetworkTemplate, subId: Int) {
- this.template = template
- this.subId = subId
- summary = null
- updateEnabled()
- intent = intent
+ setContent {
+ val isModifiable by remember {
+ context.mobileDataEnabledFlow(subId).map { repository.isModifiable(subId) }
+ }.collectAsStateWithLifecycle(initialValue = false)
+
+ Preference(object : PreferenceModel {
+ override val title = stringResource(R.string.billing_cycle)
+ override val enabled = { isModifiable }
+ override val onClick = { launchBillingCycleSettings(template) }
+ })
+ }
}
- override fun onAttached() {
- super.onAttached()
- listener.start(subId)
- }
-
- override fun onDetached() {
- listener.stop()
- super.onDetached()
- }
-
- private fun updateEnabled() {
- isEnabled = repository.isModifiable(subId)
- }
-
- override fun getIntent(): Intent {
+ private fun launchBillingCycleSettings(template: NetworkTemplate) {
val args = Bundle().apply {
putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
}
- return SubSettingLauncher(context).apply {
+ SubSettingLauncher(context).apply {
setDestination(BillingCycleSettings::class.java.name)
setArguments(args)
setTitleRes(R.string.billing_cycle)
setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
- }.toIntent()
+ }.launch()
}
}
diff --git a/src/com/android/settings/network/MobileIconGroupExt.kt b/src/com/android/settings/network/MobileIconGroupExt.kt
new file mode 100644
index 0000000..0435ef0
--- /dev/null
+++ b/src/com/android/settings/network/MobileIconGroupExt.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.network
+
+import android.content.Context
+import android.telephony.SubscriptionManager
+import android.text.Html
+import com.android.settingslib.SignalIcon
+
+fun SignalIcon.MobileIconGroup.getSummaryForSub(context: Context, subId: Int): String =
+ when (dataContentDescription) {
+ 0 -> ""
+ else -> {
+ SubscriptionManager.getResourcesForSubId(context, subId)
+ .getString(dataContentDescription)
+ }
+ }
+
+fun String.maybeToHtml(): CharSequence = when {
+ contains(HTML_TAG) -> Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
+ else -> this
+}
+
+private const val HTML_TAG = "</"
diff --git a/src/com/android/settings/network/ProviderModelSliceHelper.java b/src/com/android/settings/network/ProviderModelSliceHelper.java
index e0d1eb1..686990b 100644
--- a/src/com/android/settings/network/ProviderModelSliceHelper.java
+++ b/src/com/android/settings/network/ProviderModelSliceHelper.java
@@ -15,6 +15,7 @@
*/
package com.android.settings.network;
+import static com.android.settings.network.MobileIconGroupExtKt.maybeToHtml;
import static com.android.settings.network.telephony.MobileNetworkUtils.NO_CELL_DATA_TYPE_ICON;
import android.app.PendingIntent;
@@ -31,7 +32,6 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
@@ -176,7 +176,7 @@
protected ListBuilder.RowBuilder createCarrierRow(String networkTypeDescription) {
final String title = getMobileTitle();
- final String summary = getMobileSummary(networkTypeDescription);
+ final CharSequence summary = getMobileSummary(networkTypeDescription);
Drawable drawable = mContext.getDrawable(
R.drawable.ic_signal_strength_zero_bar_no_internet);
try {
@@ -195,7 +195,7 @@
.setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
.addEndItem(toggleAction)
.setPrimaryAction(primaryAction)
- .setSubtitle(Html.fromHtml(summary, Html.FROM_HTML_MODE_LEGACY));
+ .setSubtitle(summary);
return rowBuilder;
}
@@ -255,7 +255,7 @@
return drawable;
}
- private String getMobileSummary(String networkTypeDescription) {
+ private CharSequence getMobileSummary(String networkTypeDescription) {
if (!isMobileDataEnabled()) {
return mContext.getString(R.string.mobile_data_off_summary);
}
@@ -268,7 +268,7 @@
mContext.getString(R.string.mobile_data_connection_active),
networkTypeDescription);
}
- return summary;
+ return maybeToHtml(summary);
}
protected String getMobileTitle() {
diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java
index cc62189..0c3e6bd 100644
--- a/src/com/android/settings/network/SubscriptionsPreferenceController.java
+++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java
@@ -19,6 +19,8 @@
import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static com.android.settings.network.MobileIconGroupExtKt.getSummaryForSub;
+import static com.android.settings.network.MobileIconGroupExtKt.maybeToHtml;
import static com.android.settings.network.telephony.MobileNetworkUtils.NO_CELL_DATA_TYPE_ICON;
import static com.android.settingslib.mobile.MobileMappings.getIconKey;
import static com.android.settingslib.mobile.MobileMappings.mapIconSets;
@@ -39,7 +41,6 @@
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
-import android.text.Html;
import android.util.ArraySet;
import android.util.Log;
@@ -289,18 +290,19 @@
String result = mSubsPrefCtrlInjector.getNetworkType(mContext, mConfig,
mTelephonyDisplayInfo, subId, isCarrierNetworkActive, mCarrierNetworkChangeMode);
if (mSubsPrefCtrlInjector.isActiveCellularNetwork(mContext) || isCarrierNetworkActive) {
+ String connectionState = mContext.getString(isDds
+ ? R.string.mobile_data_connection_active
+ : R.string.mobile_data_temp_connection_active);
if (result.isEmpty()) {
- result = mContext.getString(isDds ? R.string.mobile_data_connection_active
- : R.string.mobile_data_temp_connection_active);
+ return connectionState;
} else {
- result = mContext.getString(R.string.preference_summary_default_combination,
- mContext.getString(isDds ? R.string.mobile_data_connection_active
- : R.string.mobile_data_temp_connection_active), result);
+ result = mContext.getString(
+ R.string.preference_summary_default_combination, connectionState, result);
}
} else if (!isDataInService) {
- result = mContext.getString(R.string.mobile_data_no_connection);
+ return mContext.getString(R.string.mobile_data_no_connection);
}
- return Html.fromHtml(result, Html.FROM_HTML_MODE_LEGACY);
+ return maybeToHtml(result);
}
@VisibleForTesting
@@ -579,10 +581,7 @@
return "";
}
- int resId = iconGroup.dataContentDescription;
- return resId != 0
- ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId)
- : "";
+ return getSummaryForSub(iconGroup, context, subId);
}
/**
diff --git a/src/com/android/settings/network/telephony/NetworkProviderWorker.java b/src/com/android/settings/network/telephony/NetworkProviderWorker.java
index c731bfd..ddfc031 100644
--- a/src/com/android/settings/network/telephony/NetworkProviderWorker.java
+++ b/src/com/android/settings/network/telephony/NetworkProviderWorker.java
@@ -17,6 +17,7 @@
package com.android.settings.network.telephony;
import static com.android.settings.network.InternetUpdater.INTERNET_ETHERNET;
+import static com.android.settings.network.MobileIconGroupExtKt.getSummaryForSub;
import static com.android.settingslib.mobile.MobileMappings.getIconKey;
import static com.android.settingslib.mobile.MobileMappings.mapIconSets;
@@ -284,19 +285,14 @@
private String updateNetworkTypeName(Context context, Config config,
TelephonyDisplayInfo telephonyDisplayInfo, int subId) {
- String iconKey = getIconKey(telephonyDisplayInfo);
- int resId = mapIconSets(config).get(iconKey).dataContentDescription;
if (mWifiPickerTrackerHelper != null
&& mWifiPickerTrackerHelper.isCarrierNetworkActive()) {
MobileIconGroup carrierMergedWifiIconGroup = TelephonyIcons.CARRIER_MERGED_WIFI;
- resId = carrierMergedWifiIconGroup.dataContentDescription;
- return resId != 0
- ? SubscriptionManager.getResourcesForSubId(context, subId)
- .getString(resId) : "";
+ return getSummaryForSub(carrierMergedWifiIconGroup, context, subId);
}
- return resId != 0
- ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : "";
+ String iconKey = getIconKey(telephonyDisplayInfo);
+ return getSummaryForSub(mapIconSets(config).get(iconKey), context, subId);
}
@VisibleForTesting
diff --git a/src/com/android/settings/security/ContentProtectionPreferenceFragment.java b/src/com/android/settings/security/ContentProtectionPreferenceFragment.java
index 476d93e..5c72b4d 100644
--- a/src/com/android/settings/security/ContentProtectionPreferenceFragment.java
+++ b/src/com/android/settings/security/ContentProtectionPreferenceFragment.java
@@ -34,17 +34,11 @@
public class ContentProtectionPreferenceFragment extends DashboardFragment {
private static final String TAG = "ContentProtectionPreferenceFragment";
- @VisibleForTesting
- static final String KEY_WORK_PROFILE_SWITCH =
- "content_protection_preference_user_consent_work_profile_switch";
-
// Required by @SearchIndexable to make the fragment and preferences to be indexed.
// Do not rename.
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.layout.content_protection_preference_fragment);
- private SwitchPreference mWorkProfileSwitch;
-
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -53,14 +47,6 @@
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
-
- mWorkProfileSwitch = getPreferenceScreen().findPreference(KEY_WORK_PROFILE_SWITCH);
- // If any work profile on the device, display the disable toggle unchecked
- if (Utils.getManagedProfile(getContext().getSystemService(UserManager.class)) != null) {
- mWorkProfileSwitch.setVisible(true);
- mWorkProfileSwitch.setEnabled(false);
- mWorkProfileSwitch.setChecked(false);
- }
}
@Override
diff --git a/src/com/android/settings/security/ContentProtectionWorkSwitchController.java b/src/com/android/settings/security/ContentProtectionWorkSwitchController.java
new file mode 100644
index 0000000..0404dcd
--- /dev/null
+++ b/src/com/android/settings/security/ContentProtectionWorkSwitchController.java
@@ -0,0 +1,86 @@
+/*
+ * 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.security;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+/** Preference controller for content protection work profile switch bar. */
+public class ContentProtectionWorkSwitchController extends TogglePreferenceController {
+
+ public ContentProtectionWorkSwitchController(
+ @NonNull Context context, @NonNull String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return getManagedProfile() != null ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ // The switch is always set to unchecked until Android V by design
+ @Override
+ public boolean isChecked() {
+ return false;
+ }
+
+ // The switch is disabled until Android V by design
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ return false;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ RestrictedSwitchPreference switchPreference = screen.findPreference(getPreferenceKey());
+ UserHandle managedProfile = getManagedProfile();
+ if (managedProfile != null) {
+ switchPreference.setDisabledByAdmin(getEnforcedAdmin(managedProfile));
+ }
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_security;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected UserHandle getManagedProfile() {
+ return Utils.getManagedProfile(mContext.getSystemService(UserManager.class));
+ }
+
+ @VisibleForTesting
+ @Nullable
+ protected RestrictedLockUtils.EnforcedAdmin getEnforcedAdmin(
+ @NonNull UserHandle managedProfile) {
+ return RestrictedLockUtils.getProfileOrDeviceOwner(mContext, managedProfile);
+ }
+}
diff --git a/src/com/android/settings/spa/preference/ComposePreference.kt b/src/com/android/settings/spa/preference/ComposePreference.kt
index aec85a9..aa5c32c 100644
--- a/src/com/android/settings/spa/preference/ComposePreference.kt
+++ b/src/com/android/settings/spa/preference/ComposePreference.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.util.AttributeSet
+import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
@@ -26,13 +27,23 @@
import com.android.settings.R
import com.android.settingslib.spa.framework.theme.SettingsTheme
-class ComposePreference @JvmOverloads constructor(
+open class ComposePreference @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0,
) : Preference(context, attrs, defStyleAttr, defStyleRes) {
- var content: @Composable () -> Unit = {}
+ private var content: @Composable () -> Unit = {}
+
+ fun setContent(content: @Composable () -> Unit) {
+ this.content = content
+ }
+
+ @VisibleForTesting
+ @Composable
+ fun Content() {
+ content()
+ }
init {
layoutResource = R.layout.preference_compose
diff --git a/src/com/android/settings/spa/preference/ComposePreferenceController.kt b/src/com/android/settings/spa/preference/ComposePreferenceController.kt
index 3ddb66b..9dd8282 100644
--- a/src/com/android/settings/spa/preference/ComposePreferenceController.kt
+++ b/src/com/android/settings/spa/preference/ComposePreferenceController.kt
@@ -29,7 +29,7 @@
override fun displayPreference(screen: PreferenceScreen) {
super.displayPreference(screen)
preference = screen.findPreference(preferenceKey)!!
- preference.content = { Content() }
+ preference.setContent { Content() }
}
@Composable
diff --git a/src/com/android/settings/system/ClientInitiatedActionRepository.kt b/src/com/android/settings/system/ClientInitiatedActionRepository.kt
new file mode 100644
index 0000000..24c04b4
--- /dev/null
+++ b/src/com/android/settings/system/ClientInitiatedActionRepository.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.system
+
+import android.content.Context
+import android.content.Intent
+import android.telephony.CarrierConfigManager
+import android.util.Log
+
+class ClientInitiatedActionRepository(private val context: Context) {
+ private val configManager = context.getSystemService(CarrierConfigManager::class.java)!!
+
+ /**
+ * Trigger client initiated action (send intent) on system update
+ */
+ fun onSystemUpdate() {
+ val bundle =
+ configManager.getConfig(
+ CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL,
+ CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING,
+ CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING,
+ CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING,
+ )
+
+ if (!bundle.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) return
+
+ val action =
+ bundle.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING)
+ if (action.isNullOrEmpty()) return
+ val extra = bundle.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING)
+ val extraValue =
+ bundle.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING)
+ Log.d(TAG, "onSystemUpdate: broadcasting intent $action with extra $extra, $extraValue")
+ val intent = Intent(action).apply {
+ if (!extra.isNullOrEmpty()) putExtra(extra, extraValue)
+ addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND)
+ }
+ context.applicationContext.sendBroadcast(intent)
+ }
+
+ companion object {
+ private const val TAG = "ClientInitiatedAction"
+ }
+}
diff --git a/src/com/android/settings/system/SystemUpdatePreferenceController.kt b/src/com/android/settings/system/SystemUpdatePreferenceController.kt
index 01df065..fa135aa 100644
--- a/src/com/android/settings/system/SystemUpdatePreferenceController.kt
+++ b/src/com/android/settings/system/SystemUpdatePreferenceController.kt
@@ -17,12 +17,9 @@
package com.android.settings.system
import android.content.Context
-import android.content.Intent
import android.os.Build
-import android.os.PersistableBundle
import android.os.SystemUpdateManager
import android.os.UserManager
-import android.telephony.CarrierConfigManager
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
@@ -39,6 +36,7 @@
open class SystemUpdatePreferenceController(context: Context, preferenceKey: String) :
BasePreferenceController(context, preferenceKey) {
private val userManager: UserManager = context.userManager
+ private val clientInitiatedActionRepository = ClientInitiatedActionRepository(context)
private lateinit var preference: Preference
override fun getAvailabilityStatus() =
@@ -61,12 +59,7 @@
override fun handlePreferenceTreeClick(preference: Preference): Boolean {
if (preferenceKey == preference.key) {
- val configManager = mContext.getSystemService(CarrierConfigManager::class.java)!!
- configManager.getConfig(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)?.let {
- if (it.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) {
- ciActionOnSysUpdate(it)
- }
- }
+ clientInitiatedActionRepository.onSystemUpdate()
}
// always return false here because this handler does not want to block other handlers.
return false
@@ -111,26 +104,6 @@
Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY,
)
- /**
- * Trigger client initiated action (send intent) on system update
- */
- private fun ciActionOnSysUpdate(b: PersistableBundle) {
- val intentStr = b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING)
- if (intentStr.isNullOrEmpty()) return
- val extra = b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING)
- val extraVal =
- b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING)
- Log.d(
- TAG,
- "ciActionOnSysUpdate: broadcasting intent $intentStr with extra $extra, $extraVal"
- )
- val intent = Intent(intentStr).apply {
- if (!extra.isNullOrEmpty()) putExtra(extra, extraVal)
- addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND)
- }
- mContext.applicationContext.sendBroadcast(intent)
- }
-
companion object {
private const val TAG = "SysUpdatePrefContr"
}
diff --git a/src/com/android/settings/users/MultiUserSwitchBarController.java b/src/com/android/settings/users/MultiUserSwitchBarController.java
index 33651c3..238e86e 100644
--- a/src/com/android/settings/users/MultiUserSwitchBarController.java
+++ b/src/com/android/settings/users/MultiUserSwitchBarController.java
@@ -57,11 +57,10 @@
mSwitchBar.setDisabledByAdmin(RestrictedLockUtilsInternal
.checkIfRestrictionEnforced(mContext, UserManager.DISALLOW_USER_SWITCH,
UserHandle.myUserId()));
-
} else if (mUserCapabilities.mDisallowAddUser) {
+ onSwitchToggled(false);
mSwitchBar.setDisabledByAdmin(RestrictedLockUtilsInternal
- .checkIfRestrictionEnforced(mContext, UserManager.DISALLOW_ADD_USER,
- UserHandle.myUserId()));
+ .checkIfAddUserDisallowed(mContext, UserHandle.myUserId()));
} else {
mSwitchBar.setEnabled(!mUserCapabilities.mDisallowSwitchUser
&& !mUserCapabilities.mIsGuest && mUserCapabilities.isAdmin());
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintPreferenceTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintPreferenceTest.java
index 116591d..c8c867c 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintPreferenceTest.java
@@ -21,6 +21,7 @@
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.hardware.fingerprint.Fingerprint;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
@@ -60,6 +61,21 @@
}
@Test
+ public void deleteContentDescription() {
+ final FrameLayout layout = new FrameLayout(mContext);
+ LayoutInflater.from(mContext).inflate(mPreference.getSecondTargetResId(), layout, true);
+ final String fingerprintName = "fingerprint test";
+ mPreference.setFingerprint(new Fingerprint(fingerprintName, 0, 0));
+ final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(layout);
+ mPreference.onBindViewHolder(holder);
+
+ final View view = layout.findViewById(R.id.delete_button);
+ String expectedContentDescription =
+ mContext.getString(R.string.delete) + " " + fingerprintName;
+ assertThat(view.getContentDescription().toString()).isEqualTo(expectedContentDescription);
+ }
+
+ @Test
public void bindAndClickDeleteButton_shouldInvokeOnDeleteListener() {
final FrameLayout layout = new FrameLayout(mContext);
LayoutInflater.from(mContext).inflate(mPreference.getSecondTargetResId(), layout, true);
diff --git a/tests/robotests/src/com/android/settings/security/ContentProtectionPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/security/ContentProtectionPreferenceFragmentTest.java
index c9b1c64..2bd91a6 100644
--- a/tests/robotests/src/com/android/settings/security/ContentProtectionPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/security/ContentProtectionPreferenceFragmentTest.java
@@ -18,25 +18,18 @@
import static android.app.settings.SettingsEnums.CONTENT_PROTECTION_PREFERENCE;
-import static com.android.settings.security.ContentProtectionPreferenceFragment.KEY_WORK_PROFILE_SWITCH;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.pm.UserInfo;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.SearchIndexableResource;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.R;
-import com.android.settings.Utils;
import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.ShadowDashboardFragment;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -44,13 +37,11 @@
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 java.util.Arrays;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@@ -60,14 +51,9 @@
ShadowUtils.class,
})
public class ContentProtectionPreferenceFragmentTest {
- private static final int TEST_PRIMARY_USER_ID = 10;
- private static final int TEST_MANAGED_PROFILE_ID = 11;
-
private ContentProtectionPreferenceFragment mFragment;
- @Mock private UserManager mMockUserManager;
private Context mContext;
private PreferenceScreen mScreen;
- private SwitchPreference mWorkProfileSwitch;
@Before
public void setUp() throws Exception {
@@ -79,66 +65,6 @@
doReturn(mContext).when(mFragment).getContext();
doReturn(mScreen).when(mFragment).getPreferenceScreen();
-
- mWorkProfileSwitch = new SwitchPreference(mContext);
- mWorkProfileSwitch.setVisible(false);
- doReturn(mWorkProfileSwitch).when(mScreen).findPreference(KEY_WORK_PROFILE_SWITCH);
-
- doReturn(mMockUserManager).when(mContext).getSystemService(UserManager.class);
- doReturn(TEST_PRIMARY_USER_ID).when(mMockUserManager).getUserHandle();
- UserInfo primaryUser =
- new UserInfo(
- TEST_PRIMARY_USER_ID,
- null,
- UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_PRIMARY);
- doReturn(primaryUser).when(mMockUserManager).getUserInfo(TEST_PRIMARY_USER_ID);
- UserInfo managedProfile =
- new UserInfo(
- TEST_MANAGED_PROFILE_ID,
- null,
- UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
- doReturn(managedProfile).when(mMockUserManager).getUserInfo(TEST_MANAGED_PROFILE_ID);
- }
-
- @Test
- public void onActivityCreated_workProfileDisplayWorkSwitch() {
- UserHandle[] userHandles =
- new UserHandle[] {
- new UserHandle(TEST_PRIMARY_USER_ID), new UserHandle(TEST_MANAGED_PROFILE_ID)
- };
- doReturn(Arrays.asList(userHandles)).when(mMockUserManager).getUserProfiles();
-
- assertThat(Utils.getManagedProfile(mMockUserManager).getIdentifier())
- .isEqualTo(TEST_MANAGED_PROFILE_ID);
-
- mFragment.onActivityCreated(null);
-
- assertThat(mWorkProfileSwitch.isVisible()).isTrue();
- assertThat(mWorkProfileSwitch.isChecked()).isFalse();
- assertThat(mWorkProfileSwitch.isEnabled()).isFalse();
- }
-
- @Test
- public void onActivityCreated_fullyManagedMode_bottomSwitchInvisible() {
- final ComponentName componentName =
- ComponentName.unflattenFromString("com.android.test/.DeviceAdminReceiver");
- ShadowUtils.setDeviceOwnerComponent(componentName);
-
- mFragment.onActivityCreated(null);
-
- assertThat(mWorkProfileSwitch.isVisible()).isFalse();
- }
-
- @Test
- public void onActivityCreated_personalProfileHideWorkSwitch() {
- UserHandle[] userHandles = new UserHandle[] {new UserHandle(TEST_PRIMARY_USER_ID)};
- doReturn(Arrays.asList(userHandles)).when(mMockUserManager).getUserProfiles();
-
- assertThat(Utils.getManagedProfile(mMockUserManager)).isNull();
-
- mFragment.onActivityCreated(null);
-
- assertThat(mWorkProfileSwitch.isVisible()).isFalse();
}
@Test
@@ -175,4 +101,3 @@
assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
}
}
-
diff --git a/tests/robotests/src/com/android/settings/security/ContentProtectionWorkSwitchControllerTest.java b/tests/robotests/src/com/android/settings/security/ContentProtectionWorkSwitchControllerTest.java
new file mode 100644
index 0000000..8d35e4d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/security/ContentProtectionWorkSwitchControllerTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.security;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+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;
+
+@RunWith(RobolectricTestRunner.class)
+public class ContentProtectionWorkSwitchControllerTest {
+ private static final UserHandle TEST_USER_HANDLE = UserHandle.of(10);
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ @Mock private PreferenceScreen mMockPreferenceScreen;
+ private ContentProtectionWorkSwitchController mController;
+ private UserHandle mManagedProfileUserHandle;
+ private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mController = new TestContentProtectionWorkSwitchController();
+ }
+
+ @Test
+ public void isAvailable_managedProfile_available() {
+ mManagedProfileUserHandle = TEST_USER_HANDLE;
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_noManagedProfile_notAvailable() {
+ mManagedProfileUserHandle = null;
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isChecked_noManagedProfile_alwaysOff() {
+ mManagedProfileUserHandle = null;
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_managedProfile_alwaysOff() {
+ mManagedProfileUserHandle = TEST_USER_HANDLE;
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void setChecked_alwaysFalse() {
+ assertThat(mController.setChecked(true)).isFalse();
+ assertThat(mController.setChecked(false)).isFalse();
+ }
+
+ @Test
+ public void displayPreference_managedProfile_disabled() {
+ mManagedProfileUserHandle = TEST_USER_HANDLE;
+ mEnforcedAdmin = new RestrictedLockUtils.EnforcedAdmin();
+ RestrictedSwitchPreference mockSwitchPreference = mock(RestrictedSwitchPreference.class);
+ when(mMockPreferenceScreen.findPreference(any())).thenReturn(mockSwitchPreference);
+ when(mockSwitchPreference.getKey()).thenReturn(mController.getPreferenceKey());
+
+ mController.displayPreference(mMockPreferenceScreen);
+
+ assertThat(mController.isAvailable()).isTrue();
+ verify(mockSwitchPreference).setDisabledByAdmin(mEnforcedAdmin);
+ }
+
+ @Test
+ public void displayPreference_noManagedProfile_notDisabled() {
+ mManagedProfileUserHandle = null;
+ mEnforcedAdmin = new RestrictedLockUtils.EnforcedAdmin();
+ RestrictedSwitchPreference mockSwitchPreference = mock(RestrictedSwitchPreference.class);
+ when(mMockPreferenceScreen.findPreference(any())).thenReturn(mockSwitchPreference);
+ when(mockSwitchPreference.getKey()).thenReturn(mController.getPreferenceKey());
+
+ mController.displayPreference(mMockPreferenceScreen);
+
+ assertThat(mController.isAvailable()).isFalse();
+ verify(mockSwitchPreference, never()).setDisabledByAdmin(any());
+ }
+
+ @Test
+ public void displayPreference_noEnforcedAdmin_notDisabled() {
+ mManagedProfileUserHandle = null;
+ mEnforcedAdmin = null;
+ RestrictedSwitchPreference mockSwitchPreference = mock(RestrictedSwitchPreference.class);
+ when(mMockPreferenceScreen.findPreference(any())).thenReturn(mockSwitchPreference);
+ when(mockSwitchPreference.getKey()).thenReturn(mController.getPreferenceKey());
+
+ mController.displayPreference(mMockPreferenceScreen);
+
+ assertThat(mController.isAvailable()).isFalse();
+ verify(mockSwitchPreference, never()).setDisabledByAdmin(any());
+ }
+
+ private class TestContentProtectionWorkSwitchController
+ extends ContentProtectionWorkSwitchController {
+
+ TestContentProtectionWorkSwitchController() {
+ super(ContentProtectionWorkSwitchControllerTest.this.mContext, "key");
+ }
+
+ @Override
+ @Nullable
+ protected UserHandle getManagedProfile() {
+ return mManagedProfileUserHandle;
+ }
+
+ @Override
+ @Nullable
+ protected RestrictedLockUtils.EnforcedAdmin getEnforcedAdmin(
+ @NonNull UserHandle managedProfile) {
+ return mEnforcedAdmin;
+ }
+ }
+}
diff --git a/tests/screenshot/Android.bp b/tests/screenshot/Android.bp
new file mode 100644
index 0000000..e20b5d3
--- /dev/null
+++ b/tests/screenshot/Android.bp
@@ -0,0 +1,70 @@
+//
+// 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.
+
+android_app {
+ name: "ScreenshotTestStub",
+ defaults: [
+ "SettingsLibDefaults",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ privileged: true,
+ use_resource_processor: true,
+
+ static_libs: [
+ "Settings-core",
+ "androidx.fragment_fragment-testing",
+ "androidx.fragment_fragment",
+ "androidx.test.runner",
+ "androidx.test.core",
+ ],
+ uses_libs: ["org.apache.http.legacy"],
+
+ aaptflags: ["--extra-packages com.android.settings"],
+ manifest: "AndroidManifest.xml",
+}
+
+android_test {
+ name: "SettingsScreenshotTests",
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.fragment_fragment-testing",
+ "androidx.fragment_fragment",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "platform-screenshot-diff-core",
+ "Settings-testutils2",
+ "androidx.test.core",
+ "androidx.test.espresso.core",
+ "kotlinx-coroutines-android",
+ "androidx.lifecycle_lifecycle-runtime-testing",
+ "kotlinx_coroutines_test",
+ "Settings-core",
+ "androidx.test.runner",
+ ],
+ uses_libs: ["org.apache.http.legacy"],
+ compile_multilib: "both",
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ use_embedded_native_libs: false,
+ asset_dirs: ["assets"],
+ instrumentation_for: "ScreenshotTestStub",
+ data: [":ScreenshotTestStub"],
+}
diff --git a/tests/screenshot/AndroidManifest.xml b/tests/screenshot/AndroidManifest.xml
new file mode 100644
index 0000000..9cbc882
--- /dev/null
+++ b/tests/screenshot/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.settings.tests.screenshot"
+ >
+
+ <application android:debuggable="true">
+ <provider
+ android:name="com.android.settings.slices.SettingsSliceProvider"
+ android:authorities="com.android.settings.tests.screenshot.disabled"
+ android:enabled="false"
+ tools:node="remove"
+ tools:replace="android:authorities" />
+
+ </application>
+
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Android Settings Screenshot tests"
+ android:targetPackage="com.android.settings.tests.screenshot" />
+
+</manifest>
diff --git a/tests/screenshot/AndroidTest.xml b/tests/screenshot/AndroidTest.xml
new file mode 100644
index 0000000..7496ffd
--- /dev/null
+++ b/tests/screenshot/AndroidTest.xml
@@ -0,0 +1,36 @@
+<!--
+ ~ 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.
+ -->
+
+<configuration description="Runs settings screendiff tests.">
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <option name="test-suite-tag" value="apct" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="optimized-property-setting" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="SettingsScreenshotTests.apk" />
+ </target_preparer>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys"
+ value="/data/user/0/com.android.settings.tests.screenshot/" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.settings.tests.screenshot" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git "a/tests/screenshot/assets/pixel_4a_\0505g\051/fp_enroll_intro.png" "b/tests/screenshot/assets/pixel_4a_\0505g\051/fp_enroll_intro.png"
new file mode 100644
index 0000000..1129250
--- /dev/null
+++ "b/tests/screenshot/assets/pixel_4a_\0505g\051/fp_enroll_intro.png"
Binary files differ
diff --git a/tests/screenshot/src/com/android/settings/tests/screenshot/BasicScreenshotTest.kt b/tests/screenshot/src/com/android/settings/tests/screenshot/BasicScreenshotTest.kt
new file mode 100644
index 0000000..bf28b54
--- /dev/null
+++ b/tests/screenshot/src/com/android/settings/tests/screenshot/BasicScreenshotTest.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.tests.screenshot
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.testing.FragmentScenario
+import androidx.fragment.app.testing.launchFragmentInContainer
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.settings.R
+import com.android.settings.biometrics.fingerprint2.shared.model.Default
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavState
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Start
+import com.android.settings.testutils2.FakeFingerprintManagerInteractor
+import kotlinx.coroutines.test.StandardTestDispatcher
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.screenshot.GoldenImagePathManager
+import platform.test.screenshot.ScreenshotTestRule
+import platform.test.screenshot.matchers.MSSIMMatcher
+
+@RunWith(AndroidJUnit4::class)
+class BasicScreenshotTest {
+ @Rule
+ @JvmField
+ var rule: ScreenshotTestRule =
+ ScreenshotTestRule(
+ GoldenImagePathManager(
+ InstrumentationRegistry.getInstrumentation().getContext(),
+ InstrumentationRegistry.getInstrumentation()
+ .getTargetContext()
+ .getFilesDir()
+ .getAbsolutePath() + "/settings_screenshots"
+ )
+ )
+
+ private var context: Context = ApplicationProvider.getApplicationContext()
+ private var interactor = FakeFingerprintManagerInteractor()
+
+ private val gatekeeperViewModel =
+ FingerprintGatekeeperViewModel(
+ GatekeeperInfo.GatekeeperPasswordInfo(byteArrayOf(1, 2, 3), 100L),
+ interactor
+ )
+
+ private val backgroundDispatcher = StandardTestDispatcher()
+ private lateinit var fragmentScenario: FragmentScenario<FingerprintEnrollIntroV2Fragment>
+ val navState = NavState(true)
+
+ private val navigationViewModel = FingerprintEnrollNavigationViewModel(
+ backgroundDispatcher,
+ interactor,
+ gatekeeperViewModel,
+ Start.next(navState),
+ navState,
+ Default,
+ )
+ private var fingerprintViewModel = FingerprintEnrollViewModel(
+ interactor, gatekeeperViewModel, navigationViewModel,
+ )
+ private var fingerprintScrollViewModel = FingerprintScrollViewModel()
+
+ @Before
+ fun setup() {
+ val factory =
+ object : ViewModelProvider.Factory {
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(
+ modelClass: Class<T>,
+ ): T {
+ return when (modelClass) {
+ FingerprintEnrollViewModel::class.java -> fingerprintViewModel
+ FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
+ FingerprintEnrollNavigationViewModel::class.java -> navigationViewModel
+ FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
+ else -> null
+ }
+ as T
+ }
+ }
+
+ fragmentScenario =
+ launchFragmentInContainer(Bundle(), R.style.SudThemeGlif) {
+ FingerprintEnrollIntroV2Fragment(factory)
+ }
+ }
+
+ /** Renders a [view] into a [Bitmap]. */
+ private fun viewToBitmap(view: View): Bitmap {
+ val bitmap =
+ Bitmap.createBitmap(
+ view.measuredWidth,
+ view.measuredHeight,
+ Bitmap.Config.ARGB_8888,
+ )
+ val canvas = Canvas(bitmap)
+ view.draw(canvas)
+ return bitmap
+ }
+
+ @Test
+ fun testEnrollIntro() {
+ fragmentScenario.onFragment { fragment ->
+ val view = fragment.requireView().findViewById<View>(R.id.enroll_intro_content_view)!!
+ view.setBackgroundColor(Color.BLACK)
+ }
+ fragmentScenario.onFragment { fragment ->
+ val view = fragment.requireView().findViewById<View>(R.id.enroll_intro_content_view)!!
+ rule.assertBitmapAgainstGolden(
+ viewToBitmap(view),
+ "fp_enroll_intro",
+ MSSIMMatcher()
+ )
+ }
+
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
index 2e2620b..4bf3851 100644
--- a/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
@@ -18,40 +18,69 @@
import android.content.Context
import android.net.NetworkTemplate
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
import com.android.settings.datausage.lib.BillingCycleRepository
-import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class BillingCyclePreferenceTest {
+ @get:Rule
+ val composeTestRule = createComposeRule()
- private val mockBillingCycleRepository = mock<BillingCycleRepository> {
- on { isModifiable(SUB_ID) } doReturn false
- }
+ private val mockBillingCycleRepository = mock<BillingCycleRepository>()
private val context: Context = ApplicationProvider.getApplicationContext()
private val preference = BillingCyclePreference(context, null, mockBillingCycleRepository)
@Test
- fun isEnabled_initialState() {
- val enabled = preference.isEnabled
+ fun setTemplate_titleDisplayed() {
+ setTemplate()
- assertThat(enabled).isTrue()
+ composeTestRule.onNodeWithText(context.getString(R.string.billing_cycle))
+ .assertIsDisplayed()
}
@Test
- fun isEnabled_afterSetTemplate_updated() {
+ fun setTemplate_modifiable_enabled() {
+ mockBillingCycleRepository.stub {
+ on { isModifiable(SUB_ID) } doReturn true
+ }
+
+ setTemplate()
+
+ composeTestRule.onNodeWithText(context.getString(R.string.billing_cycle)).assertIsEnabled()
+ }
+
+ @Test
+ fun setTemplate_notModifiable_notEnabled() {
+ mockBillingCycleRepository.stub {
+ on { isModifiable(SUB_ID) } doReturn false
+ }
+
+ setTemplate()
+
+ composeTestRule.onNodeWithText(context.getString(R.string.billing_cycle))
+ .assertIsNotEnabled()
+ }
+
+ private fun setTemplate() {
preference.setTemplate(mock<NetworkTemplate>(), SUB_ID)
-
- val enabled = preference.isEnabled
-
- assertThat(enabled).isFalse()
+ composeTestRule.setContent {
+ preference.Content()
+ }
}
private companion object {
diff --git a/tests/spa_unit/src/com/android/settings/network/MobileIconGroupExtTest.kt b/tests/spa_unit/src/com/android/settings/network/MobileIconGroupExtTest.kt
new file mode 100644
index 0000000..641051d
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/MobileIconGroupExtTest.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.network
+
+import android.text.Spanned
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class MobileIconGroupExtTest {
+ @Test
+ fun maybeToHtml_withoutHtmlTag() {
+ val actual = CONNECTED_5G.maybeToHtml()
+
+ assertThat(actual).isSameInstanceAs(CONNECTED_5G)
+ }
+
+ @Test
+ fun maybeToHtml_withHtmlTag() {
+ val actual = CONNECTED_5GE.maybeToHtml()
+
+ assertThat(actual).isInstanceOf(Spanned::class.java)
+ }
+
+ private companion object {
+ private const val CONNECTED_5G = "Connected / 5G"
+ private const val CONNECTED_5GE = "Connected / <i>5G <small>E</small></i>"
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/spa/preference/ComposePreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/spa/preference/ComposePreferenceControllerTest.kt
index 36817d1..cdfa514 100644
--- a/tests/spa_unit/src/com/android/settings/spa/preference/ComposePreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/preference/ComposePreferenceControllerTest.kt
@@ -61,7 +61,7 @@
controller.displayPreference(preferenceScreen)
composeTestRule.setContent {
- preference.content()
+ preference.Content()
}
composeTestRule.onNodeWithText(TEXT).assertIsDisplayed()
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/preference/ComposePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/preference/ComposePreferenceTest.kt
index 28bde3a..a2fe752 100644
--- a/tests/spa_unit/src/com/android/settings/spa/preference/ComposePreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/preference/ComposePreferenceTest.kt
@@ -43,7 +43,7 @@
@Test
fun onBindViewHolder() {
- preference.content = {
+ preference.setContent {
Text(TEXT)
}
diff --git a/tests/spa_unit/src/com/android/settings/system/ClientInitiatedActionRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/system/ClientInitiatedActionRepositoryTest.kt
new file mode 100644
index 0000000..f202668
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/system/ClientInitiatedActionRepositoryTest.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.system
+
+import android.content.Context
+import android.content.Intent
+import android.telephony.CarrierConfigManager
+import androidx.core.os.persistableBundleOf
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyVararg
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.stub
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class ClientInitiatedActionRepositoryTest {
+ private val mockCarrierConfigManager = mock<CarrierConfigManager>()
+
+ private val context = mock<Context> {
+ on { applicationContext } doReturn mock
+ on { getSystemService(CarrierConfigManager::class.java) } doReturn mockCarrierConfigManager
+ }
+
+ private val repository = ClientInitiatedActionRepository(context)
+
+ @Test
+ fun onSystemUpdate_notEnabled() {
+ mockCarrierConfigManager.stub {
+ on { getConfig(anyVararg()) } doReturn persistableBundleOf()
+ }
+
+ repository.onSystemUpdate()
+
+ verify(context, never()).sendBroadcast(any())
+ }
+
+ @Test
+ fun onSystemUpdate_enabled() {
+ mockCarrierConfigManager.stub {
+ on { getConfig(anyVararg()) } doReturn persistableBundleOf(
+ CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL to true,
+ CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING to ACTION,
+ )
+ }
+
+ repository.onSystemUpdate()
+
+ val intent = argumentCaptor<Intent> {
+ verify(context).sendBroadcast(capture())
+ }.firstValue
+ assertThat(intent.action).isEqualTo(ACTION)
+ }
+
+ private companion object {
+ const val ACTION = "ACTION"
+ }
+}
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 0f045a8..327b6aa 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -21,6 +21,7 @@
"aconfig_settings_flags_lib",
"androidx.arch.core_core-testing",
"androidx.test.core",
+ "androidx.test.espresso.core",
"androidx.test.rules",
"androidx.test.ext.junit",
"androidx.preference_preference",
diff --git a/tests/unit/src/com/android/settings/MainClearTest.kt b/tests/unit/src/com/android/settings/MainClearTest.kt
new file mode 100644
index 0000000..05f06df
--- /dev/null
+++ b/tests/unit/src/com/android/settings/MainClearTest.kt
@@ -0,0 +1,68 @@
+/*
+ * 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
+
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.core.app.ActivityScenario
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.Settings.FactoryResetActivity
+import com.android.settings.flags.Flags
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Test [MainClear]. */
+@RunWith(AndroidJUnit4::class)
+class MainClearTest {
+ @get:Rule
+ val mSetFlagsRule = SetFlagsRule()
+
+ @Test
+ fun factoryResetCancelButton_flagDisabled_noCancelButton() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_SHOW_FACTORY_RESET_CANCEL_BUTTON)
+ ActivityScenario.launch(FactoryResetActivity::class.java).use {
+ ensurePrimaryButton()
+ onView(withText(android.R.string.cancel)).check(doesNotExist())
+ it.onActivity { activity -> assertThat(activity.isFinishing).isFalse() }
+ }
+ }
+
+ @Test
+ fun factoryResetCancelButton_flagEnabled_showCancelButton() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_SHOW_FACTORY_RESET_CANCEL_BUTTON)
+ ActivityScenario.launch(FactoryResetActivity::class.java).use {
+ ensurePrimaryButton()
+ it.onActivity { activity -> assertThat(activity.isFinishing).isFalse() }
+
+ // Note: onView CANNOT be called within onActivity block, which runs in the main thread
+ onView(withText(android.R.string.cancel)).check(matches(isDisplayed())).perform(click())
+
+ it.onActivity { activity -> assertThat(activity.isFinishing).isTrue() }
+ }
+ }
+
+ private fun ensurePrimaryButton() {
+ onView(withText(R.string.main_clear_button_text)).check(matches(isDisplayed()))
+ }
+}
\ No newline at end of file
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
index 436d37f..2d63c71 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
@@ -42,7 +42,6 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.text.Html;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
@@ -56,7 +55,6 @@
import com.android.wifitrackerlib.WifiEntry;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -166,11 +164,9 @@
assertThat(testItem).isNull();
}
- @Ignore
@Test
public void createCarrierRow_hasDdsAndActiveNetworkIsNotCellular_verifyTitleAndSummary() {
String expectDisplayName = "Name1";
- CharSequence expectedSubtitle = Html.fromHtml("5G", Html.FROM_HTML_MODE_LEGACY);
String networkType = "5G";
mockConnections(true, ServiceState.STATE_IN_SERVICE, expectDisplayName,
true, true);
@@ -180,19 +176,17 @@
networkType);
assertThat(testRowBuild.getTitle()).isEqualTo(expectDisplayName);
- assertThat(testRowBuild.getSubtitle()).isEqualTo(expectedSubtitle);
+ assertThat(testRowBuild.getSubtitle()).isEqualTo("5G");
}
- @Ignore
@Test
public void createCarrierRow_wifiOnhasDdsAndActiveNetworkIsCellular_verifyTitleAndSummary() {
String expectDisplayName = "Name1";
String networkType = "5G";
String connectedText = ResourcesUtils.getResourcesString(mContext,
"mobile_data_connection_active");
- CharSequence expectedSubtitle = Html.fromHtml(ResourcesUtils.getResourcesString(mContext,
- "preference_summary_default_combination", connectedText, networkType),
- Html.FROM_HTML_MODE_LEGACY);
+ CharSequence expectedSubtitle = ResourcesUtils.getResourcesString(mContext,
+ "preference_summary_default_combination", connectedText, networkType);
mockConnections(true, ServiceState.STATE_IN_SERVICE, expectDisplayName,
true, true);
addNetworkTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
@@ -204,13 +198,11 @@
assertThat(testRowBuild.getSubtitle()).isEqualTo(expectedSubtitle);
}
- @Ignore
@Test
public void createCarrierRow_noNetworkAvailable_verifyTitleAndSummary() {
String expectDisplayName = "Name1";
- CharSequence expectedSubtitle = Html.fromHtml(
- ResourcesUtils.getResourcesString(mContext, "mobile_data_no_connection"),
- Html.FROM_HTML_MODE_LEGACY);
+ CharSequence expectedSubtitle =
+ ResourcesUtils.getResourcesString(mContext, "mobile_data_no_connection");
String networkType = "";
mockConnections(true, ServiceState.STATE_OUT_OF_SERVICE, expectDisplayName,
diff --git a/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
index c4abdd1..bca12c1 100644
--- a/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
@@ -53,7 +53,6 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
-import android.text.Html;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
@@ -266,8 +265,6 @@
@Test
@UiThreadTest
public void displayPreference_providerAndHasMultiSimAndActive_connectedAndRat() {
- final CharSequence expectedSummary =
- Html.fromHtml("Connected / 5G", Html.FROM_HTML_MODE_LEGACY);
final String networkType = "5G";
final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
@@ -281,14 +278,12 @@
mController.onResume();
mController.displayPreference(mPreferenceScreen);
- assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary);
+ assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo("Connected / 5G");
}
@Test
@UiThreadTest
public void displayPreference_providerAndHasMultiSimAndActiveCarrierWifi_connectedAndWPlus() {
- final CharSequence expectedSummary =
- Html.fromHtml("Connected / W+", Html.FROM_HTML_MODE_LEGACY);
final String networkType = "W+";
final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
@@ -302,7 +297,7 @@
mController.onResume();
mController.displayPreference(mPreferenceScreen);
- assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary);
+ assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo("Connected / W+");
}
@Test
@@ -310,8 +305,6 @@
public void displayPreference_providerAndHasMultiSimButMobileDataOff_notAutoConnect() {
final String dataOffSummary =
ResourcesUtils.getResourcesString(mContext, "mobile_data_off_summary");
- final CharSequence expectedSummary =
- Html.fromHtml(dataOffSummary, Html.FROM_HTML_MODE_LEGACY);
final String networkType = "5G";
final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
@@ -324,14 +317,12 @@
mController.onResume();
mController.displayPreference(mPreferenceScreen);
- assertThat(mPreferenceCategory.getPreference(0).getSummary())
- .isEqualTo(expectedSummary.toString());
+ assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(dataOffSummary);
}
@Test
@UiThreadTest
public void displayPreference_providerAndHasMultiSimAndNotActive_showRatOnly() {
- final CharSequence expectedSummary = Html.fromHtml("5G", Html.FROM_HTML_MODE_LEGACY);
final String networkType = "5G";
final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
@@ -345,7 +336,7 @@
mController.onResume();
mController.displayPreference(mPreferenceScreen);
- assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary);
+ assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(networkType);
}
@Test
@@ -362,8 +353,6 @@
@Test
@UiThreadTest
public void onTelephonyDisplayInfoChanged_providerAndHasMultiSimAndActive_connectedAndRat() {
- final CharSequence expectedSummary =
- Html.fromHtml("Connected / LTE", Html.FROM_HTML_MODE_LEGACY);
final String networkType = "LTE";
final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
final TelephonyDisplayInfo telephonyDisplayInfo =
@@ -383,14 +372,12 @@
mController.onTelephonyDisplayInfoChanged(sub.get(0).getSubscriptionId(),
telephonyDisplayInfo);
- assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary);
+ assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo("Connected / LTE");
}
@Test
@UiThreadTest
public void onTelephonyDisplayInfoChanged_providerAndHasMultiSimAndNotActive_showRat() {
- final CharSequence expectedSummary =
- Html.fromHtml("LTE", Html.FROM_HTML_MODE_LEGACY);
final String networkType = "LTE";
final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
final TelephonyDisplayInfo telephonyDisplayInfo =
@@ -409,7 +396,7 @@
mController.onTelephonyDisplayInfoChanged(sub.get(0).getSubscriptionId(),
telephonyDisplayInfo);
- assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary);
+ assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(networkType);
}
@Test
@@ -417,8 +404,6 @@
public void onTelephonyDisplayInfoChanged_providerAndHasMultiSimAndOutOfService_noConnection() {
final String noConnectionSummary =
ResourcesUtils.getResourcesString(mContext, "mobile_data_no_connection");
- final CharSequence expectedSummary =
- Html.fromHtml(noConnectionSummary, Html.FROM_HTML_MODE_LEGACY);
final String networkType = "LTE";
final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
final TelephonyDisplayInfo telephonyDisplayInfo =
@@ -437,7 +422,8 @@
mController.onTelephonyDisplayInfoChanged(sub.get(0).getSubscriptionId(),
telephonyDisplayInfo);
- assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary);
+ assertThat(mPreferenceCategory.getPreference(0).getSummary())
+ .isEqualTo(noConnectionSummary);
}
@Test