Snap for 12587146 from 2977bc7825 to 25Q1-release

Change-Id: Iafb0e27e4472861e6dde58785800d1141e11274a
This commit is contained in:
Android Build Coastguard Worker
2024-10-31 23:22:46 +00:00
47 changed files with 1784 additions and 98 deletions

View File

@@ -79,6 +79,7 @@ android_library {
"BiometricsSharedLib",
"SystemUIUnfoldLib",
"WifiTrackerLib",
"android.hardware.biometrics.flags-aconfig-java",
"android.hardware.dumpstate-V1-java",
"android.hardware.dumpstate-V1.0-java",
"android.hardware.dumpstate-V1.1-java",

View File

@@ -3365,6 +3365,21 @@
android:value="@string/menu_key_battery"/>
</activity>
<activity
android:name="Settings$PowerUsageAdvancedActivity"
android:label="@string/advanced_battery_title"
android:exported="true"
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize">
<intent-filter android:priority="1">
<action android:name="com.android.settings.battery.action.POWER_USAGE_ADVANCED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.fuelgauge.batteryusage.PowerUsageAdvanced" />
<meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
android:value="@string/menu_key_battery"/>
</activity>
<provider
android:name=".fuelgauge.batteryusage.BatteryUsageContentProvider"
android:enabled="true"

View File

@@ -15,3 +15,9 @@ flag {
bug: "323791114"
}
flag {
name: "catalyst_my_device_info_pref_screen"
namespace: "android_settings"
description: "Flag for About phone"
bug: "323791114"
}

View File

@@ -22,6 +22,13 @@ flag {
bug: "323791114"
}
flag {
name: "catalyst_tether_settings"
namespace: "android_settings"
description: "Flag for Hotspot & tethering"
bug: "323791114"
}
flag {
name: "catalyst_adaptive_connectivity"
namespace: "android_settings"

View File

@@ -1234,6 +1234,16 @@
<string name="security_settings_fingerprint_bad_calibration_title">Can\u2019t use fingerprint sensor</string>
<!-- Text shown during fingerprint enrollment to indicate bad sensor calibration. [CHAR LIMIT=100] -->
<string name="security_settings_fingerprint_bad_calibration">Visit a repair provider.</string>
<!-- Key for screen off udfps unlock feature. [CHAR LIMIT=NONE] -->
<string name="security_settings_screen_off_unlock_udfps_key" translatable="false">security_settings_screen_off_unlock_udfps</string>
<!-- Title for Key for screen off udfps unlock feature. [CHAR LIMIT=NONE] -->
<string name="security_settings_screen_off_unlock_udfps_title">Screen-off Fingerprint Unlock</string>
<!-- Description for screen off udfps unlock feature. [CHAR LIMIT=NONE] -->
<string name="security_settings_screen_off_unlock_udfps_description">Use Fingerprint Unlock even when the screen is off</string>
<!-- Description for screen off udfps unlock feature. [CHAR LIMIT=NONE] -->
<string name="security_settings_screen_off_unlock_udfps_keywords">Screen-off, Unlock</string>
<!-- Title for the section that has additional security settings. [CHAR LIMIT=60] -->
<string name="security_advanced_settings">More security settings</string>
<!-- String for the "More security settings" summary when a work profile is on the device. [CHAR_LIMIT=NONE] -->

View File

@@ -28,6 +28,7 @@
<com.android.settingslib.RestrictedPreference
android:key="@string/preference_key_brightness_level"
android:title="@string/brightness"
android:persistent="false"
settings:keywords="@string/keywords_display_brightness_level"
settings:useAdminDisabledSummary="true"
settings:userRestriction="no_config_brightness"/>

View File

@@ -56,7 +56,7 @@
settings:controller="com.android.settings.network.MobileNetworkSummaryController" />
<com.android.settingslib.RestrictedSwitchPreference
android:key="airplane_mode"
android:key="airplane_mode_on"
android:title="@string/airplane_mode"
android:icon="@drawable/ic_airplanemode_active"
android:order="-5"

View File

@@ -40,7 +40,16 @@
android:title="@string/security_settings_require_screen_on_to_auth_title"
android:summary="@string/security_settings_require_screen_on_to_auth_description"
settings:keywords="@string/security_settings_require_screen_on_to_auth_keywords"
settings:controller="com.android.settings.biometrics.fingerprint.FingerprintSettingsRequireScreenOnToAuthPreferenceController" />
settings:controller="com.android.settings.biometrics.fingerprint.FingerprintSettingsRequireScreenOnToAuthPreferenceController"
settings:isPreferenceVisible="false"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="@string/security_settings_screen_off_unlock_udfps_key"
android:title="@string/security_settings_screen_off_unlock_udfps_title"
android:summary="@string/security_settings_screen_off_unlock_udfps_description"
settings:keywords="@string/security_settings_screen_off_unlock_udfps_keywords"
settings:controller="com.android.settings.biometrics.fingerprint.FingerprintSettingsScreenOffUnlockUdfpsPreferenceController"
settings:isPreferenceVisible="false"/>
</PreferenceCategory>
<PreferenceCategory

View File

@@ -17,6 +17,8 @@
package com.android.settings;
import static android.content.Context.MODE_PRIVATE;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.ProgressDialog;
@@ -25,6 +27,7 @@ import android.app.admin.FactoryResetProtectionPolicy;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -33,6 +36,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.service.oemlock.OemLockManager;
import android.service.persistentdata.PersistentDataBlockManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -42,6 +46,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
import com.android.settings.network.telephony.SubscriptionActionDialogActivity;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.google.android.setupcompat.template.FooterBarMixin;
@@ -90,7 +95,7 @@ public class MainClearConfirm extends InstrumentedFragment {
} else {
pdbManager = null;
}
setSimDialogProgressState();
if (shouldWipePersistentDataBlock(pdbManager)) {
new AsyncTask<Void, Void, Void>() {
@@ -128,6 +133,17 @@ public class MainClearConfirm extends InstrumentedFragment {
} else {
doMainClear();
}
}
private void setSimDialogProgressState() {
if (getActivity() != null) {
final SharedPreferences prefs = getActivity().getSharedPreferences(
SubscriptionActionDialogActivity.SIM_ACTION_DIALOG_PREFS, MODE_PRIVATE);
prefs.edit().putInt(SubscriptionActionDialogActivity.KEY_PROGRESS_STATE,
SubscriptionActionDialogActivity.PROGRESS_IS_SHOWING).apply();
Log.d(TAG, "SIM dialog setProgressState: 1");
}
}
private ProgressDialog getProgressDialog() {

View File

@@ -484,6 +484,7 @@ public class Settings extends SettingsActivity {
public static class NetworkDashboardActivity extends SettingsActivity {}
public static class ConnectedDeviceDashboardActivity extends SettingsActivity {}
public static class PowerUsageSummaryActivity extends SettingsActivity { /* empty */ }
public static class PowerUsageAdvancedActivity extends SettingsActivity { /* empty */ }
public static class StorageDashboardActivity extends SettingsActivity {}
public static class AccountDashboardActivity extends SettingsActivity {}
public static class SystemDashboardActivity extends SettingsActivity {}

View File

@@ -16,6 +16,8 @@
package com.android.settings;
import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
import android.app.Activity;
import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
@@ -45,6 +47,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.flags.Flags;
import com.android.settings.support.actionbar.HelpResourceProvider;
import com.android.settings.widget.HighlightablePreferenceGroupAdapter;
import com.android.settings.widget.LoadingViewController;
@@ -367,9 +370,13 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF
@Override
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
final Bundle arguments = getArguments();
mAdapter = new HighlightablePreferenceGroupAdapter(preferenceScreen,
arguments == null
? null : arguments.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY),
String key = arguments == null ? null : arguments.getString(EXTRA_FRAGMENT_ARG_KEY);
if (Flags.catalyst() && key == null) {
Activity activity = getActivity();
Intent intent = activity != null ? activity.getIntent() : null;
key = intent != null ? intent.getStringExtra(EXTRA_FRAGMENT_ARG_KEY) : null;
}
mAdapter = new HighlightablePreferenceGroupAdapter(preferenceScreen, key,
mPreferenceHighlighted);
return mAdapter;
}

View File

@@ -16,8 +16,6 @@
package com.android.settings.applications;
import static android.webkit.Flags.updateServiceV2;
import android.Manifest;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -173,11 +171,9 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
}
// Keep WebView default package enabled.
if (updateServiceV2()) {
String packageName = mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName();
if (packageName != null) {
keepEnabledPackages.add(packageName);
}
String packageName = mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName();
if (packageName != null) {
keepEnabledPackages.add(packageName);
}
keepEnabledPackages.addAll(getEnabledPackageAllowlist());

View File

@@ -20,6 +20,7 @@ package com.android.settings.biometrics.fingerprint;
import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_UNLOCK_DISABLED_EXPLANATION;
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE;
import static android.app.admin.DevicePolicyResources.UNDEFINED;
import static android.hardware.biometrics.Flags.screenOffUnlockUdfps;
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
import static com.android.settings.Utils.isPrivateProfile;
@@ -207,6 +208,17 @@ public class FingerprintSettings extends SubSettings {
context,
KEY_REQUIRE_SCREEN_ON_TO_AUTH
));
} else if (screenOffUnlockUdfps()) {
controllers.add(
new FingerprintUnlockCategoryController(
context,
KEY_FINGERPRINT_UNLOCK_CATEGORY
));
controllers.add(
new FingerprintSettingsScreenOffUnlockUdfpsPreferenceController(
context,
KEY_SCREEN_OFF_FINGERPRINT_UNLOCK
));
}
controllers.add(new FingerprintsEnrolledCategoryPreferenceController(context,
KEY_FINGERPRINTS_ENROLLED_CATEGORY));
@@ -233,6 +245,9 @@ public class FingerprintSettings extends SubSettings {
@VisibleForTesting
static final String KEY_REQUIRE_SCREEN_ON_TO_AUTH =
"security_settings_require_screen_on_to_auth";
@VisibleForTesting
static final String KEY_SCREEN_OFF_FINGERPRINT_UNLOCK =
"security_settings_screen_off_unlock_udfps";
private static final String KEY_FINGERPRINTS_ENROLLED_CATEGORY =
"security_settings_fingerprints_enrolled";
private static final String KEY_FINGERPRINT_UNLOCK_CATEGORY =
@@ -263,8 +278,11 @@ public class FingerprintSettings extends SubSettings {
mFingerprintUnlockCategoryPreferenceController;
private FingerprintSettingsRequireScreenOnToAuthPreferenceController
mRequireScreenOnToAuthPreferenceController;
private FingerprintSettingsScreenOffUnlockUdfpsPreferenceController
mScreenOffUnlockUdfpsPreferenceController;
private Preference mAddFingerprintPreference;
private RestrictedSwitchPreference mRequireScreenOnToAuthPreference;
private RestrictedSwitchPreference mScreenOffUnlockUdfpsPreference;
private PreferenceCategory mFingerprintsEnrolledCategory;
private PreferenceCategory mFingerprintUnlockCategory;
private PreferenceCategory mFingerprintUnlockFooter;
@@ -621,7 +639,7 @@ public class FingerprintSettings extends SubSettings {
// This needs to be after setting ids, otherwise
// |mRequireScreenOnToAuthPreferenceController.isChecked| is always checking the primary
// user instead of the user with |mUserId|.
if (isSfps()) {
if (isSfps() || screenOffUnlockUdfps()) {
scrollToPreference(fpPrefKey);
addFingerprintUnlockCategory();
}
@@ -671,33 +689,46 @@ public class FingerprintSettings extends SubSettings {
private void addFingerprintUnlockCategory() {
mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY);
setupFingerprintUnlockCategoryPreferences();
final Preference restToUnlockPreference = FeatureFactory.getFeatureFactory()
.getFingerprintFeatureProvider()
.getSfpsRestToUnlockFeature(getContext())
.getRestToUnlockPreference(getContext());
if (restToUnlockPreference != null) {
// Use custom featured preference if any.
mRequireScreenOnToAuthPreference.setTitle(restToUnlockPreference.getTitle());
mRequireScreenOnToAuthPreference.setSummary(restToUnlockPreference.getSummary());
mRequireScreenOnToAuthPreference.setChecked(
((TwoStatePreference) restToUnlockPreference).isChecked());
mRequireScreenOnToAuthPreference.setOnPreferenceChangeListener(
restToUnlockPreference.getOnPreferenceChangeListener());
if (isSfps()) {
// For both SFPS "screen on to auth" and "rest to unlock"
final Preference restToUnlockPreference = FeatureFactory.getFeatureFactory()
.getFingerprintFeatureProvider()
.getSfpsRestToUnlockFeature(getContext())
.getRestToUnlockPreference(getContext());
if (restToUnlockPreference != null) {
// Use custom featured preference if any.
mRequireScreenOnToAuthPreference.setTitle(restToUnlockPreference.getTitle());
mRequireScreenOnToAuthPreference.setSummary(
restToUnlockPreference.getSummary());
mRequireScreenOnToAuthPreference.setChecked(
((TwoStatePreference) restToUnlockPreference).isChecked());
mRequireScreenOnToAuthPreference.setOnPreferenceChangeListener(
restToUnlockPreference.getOnPreferenceChangeListener());
}
setupFingerprintUnlockCategoryPreferencesForScreenOnToAuth();
} else if (screenOffUnlockUdfps()) {
setupFingerprintUnlockCategoryPreferencesForScreenOffUnlock();
}
updateFingerprintUnlockCategoryVisibility();
}
private void updateFingerprintUnlockCategoryVisibility() {
final boolean mFingerprintUnlockCategoryAvailable =
final boolean fingerprintUnlockCategoryAvailable =
mFingerprintUnlockCategoryPreferenceController.isAvailable();
if (mFingerprintUnlockCategory.isVisible() != mFingerprintUnlockCategoryAvailable) {
mFingerprintUnlockCategory.setVisible(
mFingerprintUnlockCategoryAvailable);
if (mFingerprintUnlockCategory.isVisible() != fingerprintUnlockCategoryAvailable) {
mFingerprintUnlockCategory.setVisible(fingerprintUnlockCategoryAvailable);
}
if (mRequireScreenOnToAuthPreferenceController != null) {
mRequireScreenOnToAuthPreference.setVisible(
mRequireScreenOnToAuthPreferenceController.isAvailable());
}
if (mScreenOffUnlockUdfpsPreferenceController != null) {
mScreenOffUnlockUdfpsPreference.setVisible(
mScreenOffUnlockUdfpsPreferenceController.isAvailable());
}
}
private void setupFingerprintUnlockCategoryPreferences() {
private void setupFingerprintUnlockCategoryPreferencesForScreenOnToAuth() {
mRequireScreenOnToAuthPreference = findPreference(KEY_REQUIRE_SCREEN_ON_TO_AUTH);
mRequireScreenOnToAuthPreference.setChecked(
mRequireScreenOnToAuthPreferenceController.isChecked());
@@ -709,9 +740,21 @@ public class FingerprintSettings extends SubSettings {
});
}
private void setupFingerprintUnlockCategoryPreferencesForScreenOffUnlock() {
mScreenOffUnlockUdfpsPreference = findPreference(KEY_SCREEN_OFF_FINGERPRINT_UNLOCK);
mScreenOffUnlockUdfpsPreference.setChecked(
mScreenOffUnlockUdfpsPreferenceController.isChecked());
mScreenOffUnlockUdfpsPreference.setOnPreferenceChangeListener(
(preference, newValue) -> {
final boolean isChecked = ((TwoStatePreference) preference).isChecked();
mScreenOffUnlockUdfpsPreferenceController.setChecked(!isChecked);
return true;
});
}
private void updatePreferencesAfterFingerprintRemoved() {
updateAddPreference();
if (isSfps()) {
if (isSfps() || screenOffUnlockUdfps()) {
updateFingerprintUnlockCategoryVisibility();
}
updatePreferences();
@@ -954,6 +997,18 @@ public class FingerprintSettings extends SubSettings {
controller;
}
}
} else if (screenOffUnlockUdfps()) {
for (AbstractPreferenceController controller : controllers) {
if (controller.getPreferenceKey() == KEY_FINGERPRINT_UNLOCK_CATEGORY) {
mFingerprintUnlockCategoryPreferenceController =
(FingerprintUnlockCategoryController) controller;
} else if (controller.getPreferenceKey() == KEY_SCREEN_OFF_FINGERPRINT_UNLOCK) {
mScreenOffUnlockUdfpsPreferenceController =
(FingerprintSettingsScreenOffUnlockUdfpsPreferenceController)
controller;
}
}
}
return controllers;
@@ -1070,7 +1125,8 @@ public class FingerprintSettings extends SubSettings {
} else if (requestCode == BIOMETRIC_AUTH_REQUEST) {
mBiometricsAuthenticationRequested = false;
if (resultCode != RESULT_OK) {
if (resultCode == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) {
if (resultCode
== ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) {
IdentityCheckBiometricErrorDialog
.showBiometricErrorDialogAndFinishActivityOnDismiss(getActivity(),
Utils.BiometricStatus.LOCKOUT);
@@ -1408,7 +1464,7 @@ public class FingerprintSettings extends SubSettings {
getContext().getSystemService(DevicePolicyManager.class);
String messageId =
isProfileChallengeUser ? WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE
: UNDEFINED;
: UNDEFINED;
int defaultMessageId = isProfileChallengeUser
? R.string.fingerprint_last_delete_message_profile_challenge
: R.string.fingerprint_last_delete_message;
@@ -1417,7 +1473,7 @@ public class FingerprintSettings extends SubSettings {
.setTitle(title)
.setMessage(devicePolicyManager.getResources().getString(
messageId,
() -> message + "\n\n" + getContext().getString(defaultMessageId)))
() -> message + "\n\n" + getContext().getString(defaultMessageId)))
.setPositiveButton(
R.string.security_settings_fingerprint_enroll_dialog_delete,
new DialogInterface.OnClickListener() {

View File

@@ -0,0 +1,119 @@
/*
* 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.biometrics.fingerprint;
import static android.hardware.biometrics.Flags.screenOffUnlockUdfps;
import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.Utils;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
/**
* Preference controller that controls whether show screen off UDFPS unlock toggle for users to
* turn this feature ON or OFF
*/
@SearchIndexable
public class FingerprintSettingsScreenOffUnlockUdfpsPreferenceController
extends FingerprintSettingsPreferenceController {
private static final String TAG =
"FingerprintSettingsScreenOffUnlockUdfpsPreferenceController";
@VisibleForTesting
protected FingerprintManager mFingerprintManager;
public FingerprintSettingsScreenOffUnlockUdfpsPreferenceController(
@NonNull Context context, @NonNull String prefKey) {
super(context, prefKey);
mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
}
@Override
public boolean isChecked() {
if (!FingerprintSettings.isFingerprintHardwareDetected(mContext)) {
return false;
} else if (getRestrictingAdmin() != null) {
return false;
}
final boolean defEnabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_screen_off_udfps_enabled);
final int value = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.SCREEN_OFF_UNLOCK_UDFPS_ENABLED,
defEnabled ? 1 : 0 /* config_screen_off_udfps_enabled */,
getUserHandle());
return value == 1;
}
@Override
public boolean setChecked(boolean isChecked) {
Settings.Secure.putIntForUser(
mContext.getContentResolver(),
Settings.Secure.SCREEN_OFF_UNLOCK_UDFPS_ENABLED,
isChecked ? 1 : 0,
getUserHandle());
return true;
}
@Override
public void updateState(@NonNull Preference preference) {
super.updateState(preference);
if (!FingerprintSettings.isFingerprintHardwareDetected(mContext)) {
preference.setEnabled(false);
} else if (!mFingerprintManager.hasEnrolledTemplates(getUserId())) {
preference.setEnabled(false);
} else if (getRestrictingAdmin() != null) {
preference.setEnabled(false);
} else {
preference.setEnabled(true);
}
}
@SuppressLint("MissingPermission")
@Override
public int getAvailabilityStatus() {
if (mFingerprintManager != null
&& mFingerprintManager.isHardwareDetected()
&& screenOffUnlockUdfps()
&& !mFingerprintManager.isPowerbuttonFps()) {
return mFingerprintManager.hasEnrolledTemplates(getUserId())
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} else {
return UNSUPPORTED_ON_DEVICE;
}
}
private int getUserHandle() {
return UserHandle.of(getUserId()).getIdentifier();
}
/**
* This feature is not directly searchable.
*/
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {};
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.biometrics.fingerprint;
import static android.hardware.biometrics.Flags.screenOffUnlockUdfps;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
@@ -42,7 +44,7 @@ public class FingerprintUnlockCategoryController extends BasePreferenceControlle
public int getAvailabilityStatus() {
if (mFingerprintManager != null
&& mFingerprintManager.isHardwareDetected()
&& mFingerprintManager.isPowerbuttonFps()) {
&& (mFingerprintManager.isPowerbuttonFps() || screenOffUnlockUdfps())) {
return mFingerprintManager.hasEnrolledTemplates(getUserId())
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} else {

View File

@@ -117,6 +117,7 @@ import com.android.settings.enterprise.EnterprisePrivacySettings;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
import com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleSettings;
import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
import com.android.settings.fuelgauge.batteryusage.PowerUsageAdvanced;
import com.android.settings.fuelgauge.batteryusage.PowerUsageSummary;
import com.android.settings.gestures.ButtonNavigationSettingsFragment;
import com.android.settings.gestures.DoubleTapPowerSettings;
@@ -276,6 +277,7 @@ public class SettingsGateway {
DevelopmentSettingsDashboardFragment.class.getName(),
WifiDisplaySettings.class.getName(),
PowerUsageSummary.class.getName(),
PowerUsageAdvanced.class.getName(),
AccountSyncSettings.class.getName(),
FaceSettings.class.getName(),
FingerprintSettings.FingerprintSettingsFragment.class.getName(),
@@ -415,6 +417,7 @@ public class SettingsGateway {
Settings.SoundSettingsActivity.class.getName(),
Settings.StorageDashboardActivity.class.getName(),
Settings.PowerUsageSummaryActivity.class.getName(),
Settings.PowerUsageAdvancedActivity.class.getName(),
Settings.AccountDashboardActivity.class.getName(),
Settings.PrivacySettingsActivity.class.getName(),
Settings.SecurityDashboardActivity.class.getName(),

View File

@@ -25,6 +25,9 @@ import android.os.Bundle;
import android.os.UserManager;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
@@ -211,6 +214,11 @@ public class MyDeviceInfoFragment extends DashboardFragment
controller.updateDeviceName(confirm);
}
@Override
public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
return MyDeviceInfoScreen.KEY;
}
/**
* For Search.
*/

View File

@@ -0,0 +1,62 @@
/*
* 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.deviceinfo.aboutphone
import android.content.Context
import android.os.Build
import android.provider.Settings
import com.android.settings.R
import com.android.settings.flags.Flags
import com.android.settingslib.metadata.PreferenceIconProvider
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.preferenceHierarchy
import com.android.settingslib.preference.PreferenceScreenCreator
@ProvidePreferenceScreen
class MyDeviceInfoScreen :
PreferenceScreenCreator, PreferenceSummaryProvider, PreferenceIconProvider {
override val key: String
get() = KEY
override val title: Int
get() = R.string.about_settings
override fun getSummary(context: Context): CharSequence? {
return Settings.Global.getString(context.contentResolver, Settings.Global.DEVICE_NAME)
?: Build.MODEL
}
override fun getIcon(context: Context): Int {
return when (Flags.homepageRevamp()) {
true -> R.drawable.ic_settings_about_device_filled
false -> R.drawable.ic_settings_about_device
}
}
override fun isFlagEnabled(context: Context) = Flags.catalystMyDeviceInfoPrefScreen()
override fun fragmentClass() = MyDeviceInfoFragment::class.java
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
override fun hasCompleteHierarchy() = false
companion object {
const val KEY = "my_device_info_pref_screen"
}
}

View File

@@ -57,6 +57,7 @@ import java.text.NumberFormat;
/**
* The top-level preference controller that updates the adaptive brightness level.
*/
// LINT.IfChange
public class BrightnessLevelPreferenceController extends BasePreferenceController implements
PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
private static final Uri BRIGHTNESS_ADJ_URI;
@@ -187,3 +188,4 @@ public class BrightnessLevelPreferenceController extends BasePreferenceControlle
return (value - min) / (max - min);
}
}
// LINT.ThenChange(BrightnessLevelRestrictedPreference.kt)

View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.display
import android.app.ActivityOptions
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_SHOW_BRIGHTNESS_DIALOG
import android.content.Intent.EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH
import android.hardware.display.BrightnessInfo
import android.hardware.display.DisplayManager
import android.hardware.display.DisplayManager.DisplayListener
import android.os.Process
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings.System
import androidx.preference.Preference
import com.android.settings.R
import com.android.settings.Utils
import com.android.settings.core.SettingsBaseActivity
import com.android.settingslib.RestrictedLockUtilsInternal
import com.android.settingslib.RestrictedPreference
import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyedObserver
import com.android.settingslib.datastore.SettingsSystemStore
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MIN
import com.android.settingslib.display.BrightnessUtils.convertLinearToGammaFloat
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.PreferenceRestrictionProvider
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.preference.PreferenceBinding
import com.android.settingslib.transition.SettingsTransitionHelper
import java.text.NumberFormat
// LINT.IfChange
class BrightnessLevelRestrictedPreference :
PreferenceMetadata,
PreferenceBinding,
PreferenceRestrictionProvider,
PreferenceSummaryProvider,
PreferenceLifecycleProvider,
Preference.OnPreferenceClickListener {
private var brightnessObserver: KeyedObserver<String>? = null
private var displayListener: DisplayListener? = null
override val key: String
get() = "brightness"
override val title: Int
get() = R.string.brightness
override val keywords: Int
get() = R.string.keywords_display_brightness_level
override fun getSummary(context: Context) =
NumberFormat.getPercentInstance().format(getCurrentBrightness(context))
override fun isEnabled(context: Context) =
!UserManager.get(context)
.hasBaseUserRestriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, Process.myUserHandle())
override fun isRestricted(context: Context) =
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context,
UserManager.DISALLOW_CONFIG_BRIGHTNESS,
UserHandle.myUserId(),
) != null
override fun createWidget(context: Context) = RestrictedPreference(context)
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
super.bind(preference, metadata)
if (preference is RestrictedPreference) preference.useAdminDisabledSummary(true)
preference.onPreferenceClickListener = this
}
override fun onStart(context: PreferenceLifecycleContext) {
val observer =
object : KeyedObserver<String> {
override fun onKeyChanged(key: String, reason: Int) {
context.notifyPreferenceChange(this@BrightnessLevelRestrictedPreference)
}
}
brightnessObserver = observer
SettingsSystemStore.get(context)
.addObserver(System.SCREEN_AUTO_BRIGHTNESS_ADJ, observer, HandlerExecutor.main)
val listener =
object : DisplayListener {
override fun onDisplayAdded(displayId: Int) {}
override fun onDisplayRemoved(displayId: Int) {}
override fun onDisplayChanged(displayId: Int) {
context.notifyPreferenceChange(this@BrightnessLevelRestrictedPreference)
}
}
displayListener = listener
context
.getSystemService(DisplayManager::class.java)
.registerDisplayListener(
listener,
HandlerExecutor.main,
DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS,
)
}
override fun onStop(context: PreferenceLifecycleContext) {
brightnessObserver?.let {
SettingsSystemStore.get(context).removeObserver(System.SCREEN_AUTO_BRIGHTNESS_ADJ, it)
brightnessObserver = null
}
displayListener?.let {
context.getSystemService(DisplayManager::class.java).unregisterDisplayListener(it)
displayListener = null
}
}
override fun onPreferenceClick(preference: Preference): Boolean {
val context = preference.context
val intent =
Intent(ACTION_SHOW_BRIGHTNESS_DIALOG)
.setPackage(Utils.SYSTEMUI_PACKAGE_NAME)
.putExtra(
SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
SettingsTransitionHelper.TransitionType.TRANSITION_NONE,
)
.putExtra(EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH, true)
val options =
ActivityOptions.makeCustomAnimation(
context,
android.R.anim.fade_in,
android.R.anim.fade_out,
)
context.startActivityForResult(preference.key, intent, 0, options.toBundle())
return true
}
private fun getCurrentBrightness(context: Context): Double {
val info: BrightnessInfo? = context.display.brightnessInfo
val value =
info?.run {
convertLinearToGammaFloat(brightness, brightnessMinimum, brightnessMaximum)
}
return getPercentage(value?.toDouble() ?: 0.0)
}
private fun getPercentage(value: Double): Double =
when {
value > GAMMA_SPACE_MAX -> 1.0
value < GAMMA_SPACE_MIN -> 0.0
else -> (value - GAMMA_SPACE_MIN) / (GAMMA_SPACE_MAX - GAMMA_SPACE_MIN)
}
}
// LINT.ThenChange(BrightnessLevelPreferenceController.java)

View File

@@ -18,10 +18,13 @@ package com.android.settings.display
import android.content.Context
import com.android.settings.DisplaySettings
import com.android.settings.R
import com.android.settings.Settings.DisplaySettingsActivity
import com.android.settings.display.darkmode.DarkModeScreen
import com.android.settings.flags.Flags
import com.android.settings.utils.makeLaunchIntent
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceIconProvider
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.preferenceHierarchy
import com.android.settingslib.preference.PreferenceScreenCreator
@@ -48,10 +51,14 @@ class DisplayScreen :
override fun fragmentClass() = DisplaySettings::class.java
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
+BrightnessLevelRestrictedPreference()
+DarkModeScreen.KEY
+PeakRefreshRateSwitchPreference()
}
override fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?) =
makeLaunchIntent(context, DisplaySettingsActivity::class.java, metadata?.key)
override fun isAvailable(context: Context) =
context.resources.getBoolean(R.bool.config_show_top_level_display)

View File

@@ -18,53 +18,51 @@ package com.android.settings.display
import android.content.Context
import android.hardware.display.DisplayManager
import android.provider.DeviceConfig
import android.util.Log
import android.provider.Settings.System.PEAK_REFRESH_RATE
import com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE
import com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays
import com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay
import com.android.server.display.feature.flags.Flags
import com.android.settings.R
import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyedObservableDelegate
import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.datastore.SettingsSystemStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.SwitchPreference
import com.android.settingslib.preference.SwitchPreferenceBinding
import kotlin.math.roundToInt
// LINT.IfChange
class PeakRefreshRateSwitchPreference :
SwitchPreference("peak_refresh_rate", R.string.peak_refresh_rate_title),
SwitchPreferenceBinding,
SwitchPreference(PEAK_REFRESH_RATE, R.string.peak_refresh_rate_title),
PreferenceAvailabilityProvider,
PreferenceSummaryProvider,
PreferenceLifecycleProvider {
private var propertiesChangedListener: DeviceConfig.OnPropertiesChangedListener? = null
override fun storage(context: Context) = SettingsSystemStore.get(context)
override fun storage(context: Context): KeyValueStore =
PeakRefreshRateStore(context, SettingsSystemStore.get(context))
override fun isAvailable(context: Context) =
context.resources.getBoolean(R.bool.config_show_smooth_display) &&
(getPeakRefreshRate(context) > DEFAULT_REFRESH_RATE)
context.peakRefreshRate > DEFAULT_REFRESH_RATE
override fun getSummary(context: Context) =
context.getString(
R.string.peak_refresh_rate_summary,
getPeakRefreshRate(context).roundToInt(),
)
override fun getSummary(context: Context): CharSequence? =
context.getString(R.string.peak_refresh_rate_summary, context.peakRefreshRate.roundToInt())
override fun onStart(context: PreferenceLifecycleContext) {
val listener =
object : DeviceConfig.OnPropertiesChangedListener {
DeviceConfig.OnPropertiesChangedListener {
// Got notified if any property has been changed in NAMESPACE_DISPLAY_MANAGER. The
// KEY_PEAK_REFRESH_RATE_DEFAULT value could be added, changed, removed or
// unchanged.
// Just force a UI update for any case.
override fun onPropertiesChanged(properties: DeviceConfig.Properties) =
context.notifyPreferenceChange(this@PeakRefreshRateSwitchPreference)
context.notifyPreferenceChange(this)
}
propertiesChangedListener = listener
@@ -83,38 +81,74 @@ class PeakRefreshRateSwitchPreference :
}
}
private fun getPeakRefreshRate(context: Context): Float =
Math.round(
when {
Flags.backUpSmoothDisplayAndForcePeakRefreshRate() ->
findHighestRefreshRateAmongAllDisplays(context)
else -> findHighestRefreshRateForDefaultDisplay(context)
}
)
.toFloat()
@Suppress("UNCHECKED_CAST")
private class PeakRefreshRateStore(
private val context: Context,
private val settingsStore: SettingsStore,
) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
private fun getDefaultPeakRefreshRate(context: Context): Float {
var defaultPeakRefreshRate =
DeviceConfig.getFloat(
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT,
INVALIDATE_REFRESH_RATE,
)
override fun contains(key: String) = settingsStore.contains(key)
if (defaultPeakRefreshRate == INVALIDATE_REFRESH_RATE) {
defaultPeakRefreshRate =
context.resources
.getInteger(com.android.internal.R.integer.config_defaultPeakRefreshRate)
.toFloat()
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>): T? {
if (key != PEAK_REFRESH_RATE) return super.getDefaultValue(key, valueType)
return context.defaultPeakRefreshRate.refreshRateAsBoolean(context) as T
}
Log.d(TAG, "DeviceConfig getDefaultPeakRefreshRate : $defaultPeakRefreshRate")
return defaultPeakRefreshRate
override fun <T : Any> getValue(key: String, valueType: Class<T>): T? {
if (key != PEAK_REFRESH_RATE) return null
val refreshRate =
settingsStore.getFloat(PEAK_REFRESH_RATE) ?: context.defaultPeakRefreshRate
return refreshRate.refreshRateAsBoolean(context) as T
}
private fun Float.refreshRateAsBoolean(context: Context) =
this.isInfinite() || roundToInt() == context.peakRefreshRate.roundToInt()
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
when {
key != PEAK_REFRESH_RATE -> {}
value == null -> settingsStore.setFloat(PEAK_REFRESH_RATE, null)
else -> {
val peakRefreshRate =
if (value as Boolean) context.refreshRateIfON() else DEFAULT_REFRESH_RATE
settingsStore.setFloat(PEAK_REFRESH_RATE, peakRefreshRate)
}
}
private fun Context.refreshRateIfON() =
when {
Flags.backUpSmoothDisplayAndForcePeakRefreshRate() -> Float.POSITIVE_INFINITY
else -> peakRefreshRate
}
}
companion object {
private const val TAG: String = "PeakRefreshRateSwitchPreference"
private const val INVALIDATE_REFRESH_RATE: Float = -1f
private val Context.peakRefreshRate: Float
get() =
Math.round(
when {
Flags.backUpSmoothDisplayAndForcePeakRefreshRate() ->
findHighestRefreshRateAmongAllDisplays(this)
else -> findHighestRefreshRateForDefaultDisplay(this)
}
)
.toFloat()
private val Context.defaultPeakRefreshRate: Float
get() {
val defaultPeakRefreshRate =
DeviceConfig.getFloat(
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT,
INVALIDATE_REFRESH_RATE,
)
if (defaultPeakRefreshRate != INVALIDATE_REFRESH_RATE) return defaultPeakRefreshRate
return resources
.getInteger(com.android.internal.R.integer.config_defaultPeakRefreshRate)
.toFloat()
}
}
}
// LINT.ThenChange(PeakRefreshRatePreferenceController.java)

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network
import android.content.Context
import android.content.pm.PackageManager
import android.provider.Settings.Global.AIRPLANE_MODE_ON
import androidx.annotation.DrawableRes
import com.android.settings.R
import com.android.settingslib.datastore.SettingsGlobalStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.SwitchPreference
// LINT.IfChange
class AirplaneModePreference :
SwitchPreference(AIRPLANE_MODE_ON, R.string.airplane_mode),
PreferenceAvailabilityProvider {
override val icon: Int
@DrawableRes get() = R.drawable.ic_airplanemode_active
override fun storage(context: Context) = SettingsGlobalStore.get(context)
override fun isAvailable(context: Context) =
(context.resources.getBoolean(R.bool.config_show_toggle_airplane)
&& !context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
}
// LINT.ThenChange(AirplaneModePreferenceController.java)

View File

@@ -52,6 +52,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
// LINT.IfChange
public class AirplaneModePreferenceController extends TogglePreferenceController
implements LifecycleObserver, OnStart, OnResume, OnStop, OnDestroy,
AirplaneModeEnabler.OnAirplaneModeChangedListener {
@@ -217,3 +218,4 @@ public class AirplaneModePreferenceController extends TogglePreferenceController
}
}
}
// LINT.ThenChange(AirplaneModePreference.kt)

View File

@@ -26,7 +26,6 @@ import android.net.VpnManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.SettingsSlicesContract;
import android.security.Credentials;
import android.security.LegacyVpnProfileStore;
import android.util.Log;
@@ -39,7 +38,6 @@ import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.vpn2.VpnInfoPreference;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -50,7 +48,6 @@ import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.utils.ThreadUtils;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class VpnPreferenceController extends AbstractPreferenceController
@@ -87,7 +84,7 @@ public class VpnPreferenceController extends AbstractPreferenceController
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
// Manually set dependencies for Wifi when not toggleable.
if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_WIFI)) {
preference.setDependency(SettingsSlicesContract.KEY_AIRPLANE_MODE);
preference.setDependency(Settings.Global.AIRPLANE_MODE_ON);
}
return preference;
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network.tether
import android.content.Context
import android.net.TetheringManager
import com.android.settings.R
import com.android.settings.flags.Flags
import com.android.settings.network.TetherPreferenceController
import com.android.settingslib.TetherUtil
import com.android.settingslib.Utils
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 TetherScreen : PreferenceScreenCreator, PreferenceAvailabilityProvider {
override val key: String
get() = KEY
override val icon: Int
get() = R.drawable.ic_wifi_tethering
override val keywords: Int
get() = R.string.keywords_hotspot_tethering
override fun getPreferenceTitle(context: Context): CharSequence? =
if (TetherPreferenceController.isTetherConfigDisallowed(context)) {
context.getText(R.string.tether_settings_title_all)
} else {
val tetheringManager = context.getSystemService(TetheringManager::class.java)!!
context.getText(Utils.getTetheringLabel(tetheringManager))
}
override fun isAvailable(context: Context) = TetherUtil.isTetherAvailable(context)
override fun isFlagEnabled(context: Context) = Flags.catalystTetherSettings()
override fun hasCompleteHierarchy() = false
override fun fragmentClass() = TetherSettings::class.java
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
companion object {
const val KEY = "tether_settings"
}
}

View File

@@ -48,6 +48,7 @@ import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.Preference;
@@ -731,4 +732,9 @@ public class TetherSettings extends RestrictedDashboardFragment
}
updateBluetoothAndEthernetState();
}
@Override
public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
return TetherScreen.KEY;
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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.notification
import android.content.Context
import android.media.AudioManager.STREAM_MUSIC
import android.os.UserHandle
import android.os.UserManager
import androidx.preference.Preference
import com.android.settings.R
import com.android.settingslib.RestrictedLockUtilsInternal
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.NoOpKeyedObservable
import com.android.settingslib.metadata.*
import com.android.settingslib.preference.PreferenceBinding
// LINT.IfChange
open class MediaVolumePreference :
PreferenceMetadata,
PreferenceBinding,
PersistentPreference<Int>,
RangeValue,
PreferenceAvailabilityProvider,
PreferenceIconProvider,
PreferenceRestrictionProvider {
override val key: String
get() = KEY
override val title: Int
get() = R.string.media_volume_option_title
override fun getIcon(context: Context) =
when {
VolumeHelper.isMuted(context, STREAM_MUSIC) -> R.drawable.ic_media_stream_off
else -> R.drawable.ic_media_stream
}
override fun isAvailable(context: Context) =
context.resources.getBoolean(R.bool.config_show_media_volume)
override fun isRestricted(context: Context) =
RestrictedLockUtilsInternal.hasBaseUserRestriction(
context,
UserManager.DISALLOW_ADJUST_VOLUME,
UserHandle.myUserId(),
) ||
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context,
UserManager.DISALLOW_ADJUST_VOLUME,
UserHandle.myUserId(),
) != null
override fun storage(context: Context): KeyValueStore {
val helper = createAudioHelper(context)
return object : NoOpKeyedObservable<String>(), KeyValueStore {
override fun contains(key: String) = key == KEY
@Suppress("UNCHECKED_CAST")
override fun <T : Any> getValue(key: String, valueType: Class<T>) =
helper.getStreamVolume(STREAM_MUSIC) as T
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
helper.setStreamVolume(STREAM_MUSIC, value as Int)
}
}
}
override fun getMinValue(context: Context) =
createAudioHelper(context).getMinVolume(STREAM_MUSIC)
override fun getMaxValue(context: Context) =
createAudioHelper(context).getMaxVolume(STREAM_MUSIC)
override fun createWidget(context: Context) = VolumeSeekBarPreference(context)
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
super.bind(preference, metadata)
(preference as VolumeSeekBarPreference).apply {
setStream(STREAM_MUSIC)
setMuteIcon(R.drawable.ic_media_stream_off)
setListener { updateContentDescription(this) }
}
}
open fun createAudioHelper(context: Context) = AudioHelper(context)
fun updateContentDescription(preference: VolumeSeekBarPreference) {
when {
preference.isMuted() ->
preference.updateContentDescription(
preference.context.getString(
R.string.volume_content_description_silent_mode,
preference.title,
)
)
else -> preference.updateContentDescription(preference.title)
}
}
companion object {
const val KEY = "media_volume"
}
}
// LINT.ThenChange(MediaVolumePreferenceController.java)

View File

@@ -42,6 +42,7 @@ import com.android.settingslib.media.BluetoothMediaDevice;
import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.MediaOutputConstants;
// LINT.IfChange
public class MediaVolumePreferenceController extends VolumeSeekBarPreferenceController {
private static final String TAG = "MediaVolumePreCtrl";
private static final String KEY_MEDIA_VOLUME = "media_volume";
@@ -204,3 +205,4 @@ public class MediaVolumePreferenceController extends VolumeSeekBarPreferenceCont
return MediaOutputIndicatorWorker.class;
}
}
// LINT.ThenChange(MediaVolumePreference.kt)

View File

@@ -0,0 +1,172 @@
/*
* 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.notification
import android.app.INotificationManager
import android.app.NotificationManager
import android.content.Context
import android.media.AudioManager.RINGER_MODE_NORMAL
import android.media.AudioManager.RINGER_MODE_SILENT
import android.media.AudioManager.RINGER_MODE_VIBRATE
import android.media.AudioManager.STREAM_RING
import android.os.ServiceManager
import android.os.UserHandle
import android.os.UserManager.DISALLOW_ADJUST_VOLUME
import android.os.Vibrator
import android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS
import android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS
import androidx.preference.Preference
import com.android.settings.R
import com.android.settingslib.RestrictedLockUtilsInternal
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.NoOpKeyedObservable
import com.android.settingslib.metadata.PersistentPreference
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceIconProvider
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.PreferenceRestrictionProvider
import com.android.settingslib.metadata.RangeValue
import com.android.settingslib.preference.PreferenceBinding
// LINT.IfChange
open class SeparateRingVolumePreference :
PreferenceMetadata,
PreferenceBinding,
PersistentPreference<Int>,
RangeValue,
PreferenceAvailabilityProvider,
PreferenceIconProvider,
PreferenceRestrictionProvider {
override val key: String
get() = KEY
override val title: Int
get() = R.string.separate_ring_volume_option_title
override fun getIcon(context: Context) =
when {
VolumeHelper.isMuted(context, STREAM_RING) -> getMuteIcon(context)
else -> R.drawable.ic_ring_volume
}
override fun isAvailable(context: Context) = !createAudioHelper(context).isSingleVolume()
override fun isEnabled(context: Context) =
!RestrictedLockUtilsInternal.hasBaseUserRestriction(
context,
DISALLOW_ADJUST_VOLUME,
UserHandle.myUserId(),
)
override fun isRestricted(context: Context) =
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context,
DISALLOW_ADJUST_VOLUME,
UserHandle.myUserId(),
) != null
override fun storage(context: Context): KeyValueStore {
val helper = createAudioHelper(context)
return object : NoOpKeyedObservable<String>(), KeyValueStore {
override fun contains(key: String) = key == KEY
@Suppress("UNCHECKED_CAST")
override fun <T : Any> getValue(key: String, valueType: Class<T>) =
helper.getStreamVolume(STREAM_RING) as T
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
helper.setStreamVolume(STREAM_RING, value as Int)
}
}
}
override fun getMinValue(context: Context) =
createAudioHelper(context).getMinVolume(STREAM_RING)
override fun getMaxValue(context: Context) =
createAudioHelper(context).getMaxVolume(STREAM_RING)
override fun createWidget(context: Context) = VolumeSeekBarPreference(context)
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
super.bind(preference, metadata)
(preference as VolumeSeekBarPreference).apply {
setStream(STREAM_RING)
setMuteIcon(getMuteIcon(preference.context))
setListener { updateContentDescription(this) }
setSuppressionText(getSuppressionText(preference.context))
}
}
open fun createAudioHelper(context: Context) = AudioHelper(context)
fun updateContentDescription(preference: VolumeSeekBarPreference) {
val context = preference.context
val ringerMode = getEffectiveRingerMode(context)
when (ringerMode) {
RINGER_MODE_VIBRATE ->
preference.updateContentDescription(
context.getString(R.string.ringer_content_description_vibrate_mode)
)
RINGER_MODE_SILENT ->
preference.updateContentDescription(
context.getString(R.string.ringer_content_description_silent_mode)
)
else -> preference.updateContentDescription(preference.title)
}
}
fun getMuteIcon(context: Context): Int {
val ringerMode = getEffectiveRingerMode(context)
return when (ringerMode) {
RINGER_MODE_NORMAL -> R.drawable.ic_ring_volume
RINGER_MODE_VIBRATE -> R.drawable.ic_volume_ringer_vibrate
else -> R.drawable.ic_ring_volume_off
}
}
fun getEffectiveRingerMode(context: Context): Int {
val hasVibrator = context.getSystemService(Vibrator::class.java)?.hasVibrator() ?: false
val ringerMode = createAudioHelper(context).ringerModeInternal
return when {
!hasVibrator && ringerMode == RINGER_MODE_VIBRATE -> RINGER_MODE_SILENT
else -> ringerMode
}
}
fun getSuppressionText(context: Context): String? {
val suppressor = NotificationManager.from(context).getEffectsSuppressor()
val notificationManager =
INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE)
)
val hints = notificationManager.getHintsFromListenerNoToken()
return when {
hintsMatch(hints) -> SuppressorHelper.getSuppressionText(context, suppressor)
else -> null
}
}
private fun hintsMatch(hints: Int) =
(hints and HINT_HOST_DISABLE_CALL_EFFECTS) != 0 ||
(hints and HINT_HOST_DISABLE_EFFECTS) != 0
companion object {
const val KEY = "separate_ring_volume"
}
}
// LINT.ThenChange(SeparateRingVolumePreferenceController.java)

View File

@@ -35,6 +35,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
/**
* This slider is used to represent ring volume when ring is separated from notification
*/
// LINT.IfChange
public class SeparateRingVolumePreferenceController extends
RingerModeAffectedVolumePreferenceController {
@@ -149,3 +150,4 @@ public class SeparateRingVolumePreferenceController extends
}
}
// LINT.ThenChange(SeparateRingVolumePreference.kt)

View File

@@ -49,7 +49,9 @@ class SoundScreen : PreferenceScreenCreator, PreferenceIconProvider {
override fun getPreferenceHierarchy(context: Context) =
preferenceHierarchy(this) {
+MediaVolumePreference() order -180
+CallVolumePreference() order -170
+SeparateRingVolumePreference() order -155
+DialPadTonePreference() order -50
}

View File

@@ -0,0 +1,62 @@
/*
* 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.notification
import android.app.NotificationManager
import android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS
import android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA
import android.content.Context
import android.media.AudioManager
import android.media.AudioManager.*
import android.provider.Settings.Global.ZEN_MODE_ALARMS
import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
import android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
import android.service.notification.ZenModeConfig
class VolumeHelper {
companion object {
fun isMuted(context: Context, streamType: Int): Boolean {
val audioManager = context.getSystemService(AudioManager::class.java)
return audioManager.isStreamMute(streamType) && !isZenMuted(context, streamType)
}
fun isZenMuted(context: Context, streamType: Int): Boolean {
val notificationManager = context.getSystemService(NotificationManager::class.java)
val zenMode = notificationManager.getZenMode()
val notificationPolicy = notificationManager.getConsolidatedNotificationPolicy()
val isAllowAlarms =
(notificationPolicy.priorityCategories and PRIORITY_CATEGORY_ALARMS) != 0
val isAllowMedia =
(notificationPolicy.priorityCategories and PRIORITY_CATEGORY_MEDIA) != 0
val isAllowRinger =
!ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(notificationPolicy)
return isNotificationOrRingStream(streamType)
&& zenMode == ZEN_MODE_ALARMS || zenMode == ZEN_MODE_NO_INTERRUPTIONS
|| (zenMode == ZEN_MODE_IMPORTANT_INTERRUPTIONS
&& (!isAllowRinger && isNotificationOrRingStream(streamType)
|| !isAllowMedia && isMediaStream(streamType)
|| !isAllowAlarms && isAlarmStream(streamType)))
}
private fun isNotificationOrRingStream(streamType: Int) =
streamType == STREAM_RING || streamType == STREAM_NOTIFICATION
private fun isAlarmStream(streamType: Int) = streamType == STREAM_ALARM
private fun isMediaStream(streamType: Int) = streamType == STREAM_MUSIC
}
}

View File

@@ -377,7 +377,14 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity {
setBiometricPromptPropertiesForPrivateProfile(promptInfo);
showBiometricPrompt(promptInfo, effectiveUserId);
launchedBiometric = true;
} else if (Flags.privateSpaceBp()) {
promptInfo.setAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL);
setBiometricPromptPropertiesForPrivateProfile(promptInfo);
showBiometricPrompt(promptInfo, mUserId);
launchedBiometric = true;
} else {
// TODO(b/376328272): Remove custom private space behavior
mDetails = Utils.getConfirmCredentialStringForUser(this, mUserId, credentialType);
showConfirmCredentials();
launchedCDC = true;
}

View File

@@ -0,0 +1,34 @@
/*
* 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.utils
import android.app.Activity
import android.content.Context
import android.content.Intent
import com.android.settings.SettingsActivity
/**
* Returns the [Intent] to start given settings activity and locate the preference.
*
* @param context context
* @param activityClass activity to start
* @param key preference key to locate
*/
fun makeLaunchIntent(context: Context, activityClass: Class<out Activity>, key: String?) =
Intent(context, activityClass).apply {
if (key != null) putExtra(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, key)
}

View File

@@ -30,6 +30,7 @@ import android.util.TypedValue;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceGroupAdapter;
@@ -64,7 +65,7 @@ public class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter
private final Context mContext;
private final int mNormalBackgroundRes;
private final String mHighlightKey;
private final @Nullable String mHighlightKey;
private boolean mHighlightRequested;
private int mHighlightPosition = RecyclerView.NO_POSITION;
@@ -101,7 +102,8 @@ public class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter
screen.setInitialExpandedChildrenCount(initialCount);
}
public HighlightablePreferenceGroupAdapter(PreferenceGroup preferenceGroup, String key,
public HighlightablePreferenceGroupAdapter(PreferenceGroup preferenceGroup,
@Nullable String key,
boolean highlightRequested) {
super(preferenceGroup);
mHighlightKey = key;

View File

@@ -38,11 +38,8 @@ import android.os.Build;
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.webkit.Flags;
import com.android.settings.testutils.ApplicationTestUtils;
import com.android.settings.webview.WebViewUpdateServiceWrapper;
@@ -373,7 +370,6 @@ public final class ApplicationFeatureProviderImplTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_UPDATE_SERVICE_V2)
public void getKeepEnabledPackages_shouldContainWebViewPackage() {
final String testWebViewPackageName = "com.android.webview";
when(mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName())
@@ -382,16 +378,6 @@ public final class ApplicationFeatureProviderImplTest {
assertThat(allowlist).contains(testWebViewPackageName);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_UPDATE_SERVICE_V2)
public void getKeepEnabledPackages_shouldNotContainWebViewPackageIfFlagDisabled() {
final String testWebViewPackageName = "com.android.webview";
when(mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName())
.thenReturn(testWebViewPackageName);
final Set<String> allowlist = mProvider.getKeepEnabledPackages();
assertThat(allowlist).doesNotContain(testWebViewPackageName);
}
@Test
@Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class})
public void getKeepEnabledPackages_shouldContainPackageInstaller() {

View File

@@ -0,0 +1,157 @@
/*
* 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.biometrics.fingerprint;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settingslib.RestrictedSwitchPreference;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowUtils.class})
public class FingerprintSettingsScreenOffUnlockUdfpsPreferenceControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Mock
private FingerprintManager mFingerprintManager;
@Mock
private PackageManager mPackageManager;
@Mock
private RestrictedSwitchPreference mPreference;
private Context mContext;
private FingerprintSettingsScreenOffUnlockUdfpsPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(eq(Context.FINGERPRINT_SERVICE))).thenReturn(
mFingerprintManager);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
mController = spy(new FingerprintSettingsScreenOffUnlockUdfpsPreferenceController(mContext,
"test_key"));
ReflectionHelpers.setField(mController, "mFingerprintManager", mFingerprintManager);
}
@After
public void tearDown() {
ShadowUtils.reset();
}
@Test
public void onPreferenceChange_settingIsUpdated() {
boolean state = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.SCREEN_OFF_UNLOCK_UDFPS_ENABLED, 1) != 0;
assertThat(mController.isChecked()).isFalse();
assertThat(mController.onPreferenceChange(mPreference, !state)).isTrue();
boolean newState = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.SCREEN_OFF_UNLOCK_UDFPS_ENABLED, 1) != 0;
assertThat(newState).isEqualTo(!state);
}
@Test
@EnableFlags(android.hardware.biometrics.Flags.FLAG_SCREEN_OFF_UNLOCK_UDFPS)
public void isAvailable_isEnabled_whenUdfpsHardwareDetected_AndHasEnrolledFingerprints() {
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isUdfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
false /* isPowerbuttonFps false implies udfps */,
true /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isEqualTo(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
@EnableFlags(android.hardware.biometrics.Flags.FLAG_SCREEN_OFF_UNLOCK_UDFPS)
public void isUnavailable_isDisabled_whenUdfpsHardwareDetected_AndNoEnrolledFingerprints() {
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isUdfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
false /* isPowerbuttonFps false implies udfps */,
false /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
@EnableFlags(android.hardware.biometrics.Flags.FLAG_SCREEN_OFF_UNLOCK_UDFPS)
public void isUnavailable_whenHardwareNotDetected() {
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isUdfps_hasEnrolledTemplates(
false /* isHardwareDetected */,
false /* isPowerbuttonFps false implies udfps */,
true /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
@EnableFlags(android.hardware.biometrics.Flags.FLAG_SCREEN_OFF_UNLOCK_UDFPS)
public void isUnavailable_onNonUdfpsDevice() {
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isUdfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
true /* isPowerbuttonFps false implies udfps */,
true /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
private void configure_hardwareDetected_isUdfps_hasEnrolledTemplates(
boolean isHardwareDetected, boolean isPowerbuttonFps, boolean hasEnrolledTemplates) {
when(mFingerprintManager.isHardwareDetected()).thenReturn(isHardwareDetected);
when(mFingerprintManager.isPowerbuttonFps()).thenReturn(isPowerbuttonFps);
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(hasEnrolledTemplates);
}
}

View File

@@ -30,12 +30,15 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settingslib.RestrictedSwitchPreference;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -49,6 +52,8 @@ import org.robolectric.util.ReflectionHelpers;
@Config(shadows = {ShadowUtils.class})
public class FingerprintSettingsUnlockCategoryControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Mock
private FingerprintManager mFingerprintManager;
@Mock
@@ -59,6 +64,8 @@ public class FingerprintSettingsUnlockCategoryControllerTest {
private Context mContext;
private FingerprintSettingsRequireScreenOnToAuthPreferenceController mController;
private FingerprintSettingsScreenOffUnlockUdfpsPreferenceController mScreenOffUnlockController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -69,7 +76,12 @@ public class FingerprintSettingsUnlockCategoryControllerTest {
mController = spy(new FingerprintSettingsRequireScreenOnToAuthPreferenceController(mContext,
"test_key"));
mScreenOffUnlockController = spy(
new FingerprintSettingsScreenOffUnlockUdfpsPreferenceController(mContext,
"screen_off_unlock_test_key"));
ReflectionHelpers.setField(mController, "mFingerprintManager", mFingerprintManager);
ReflectionHelpers.setField(mScreenOffUnlockController, "mFingerprintManager",
mFingerprintManager);
}
@After
@@ -89,6 +101,20 @@ public class FingerprintSettingsUnlockCategoryControllerTest {
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
@EnableFlags(android.hardware.biometrics.Flags.FLAG_SCREEN_OFF_UNLOCK_UDFPS)
public void isAvailable_isEnabled_whenUdfpsHardwareDetected_AndHasEnrolledFingerprints() {
assertThat(mScreenOffUnlockController.isAvailable()).isEqualTo(false);
assertThat(mScreenOffUnlockController.getAvailabilityStatus()).isEqualTo(
UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
false /* isPowerbuttonFps false implies udfps */,
true /* hasEnrolledTemplates */);
assertThat(mScreenOffUnlockController.isAvailable()).isEqualTo(true);
assertThat(mScreenOffUnlockController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void isUnavailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() {
assertThat(mController.isAvailable()).isEqualTo(false);
@@ -102,7 +128,22 @@ public class FingerprintSettingsUnlockCategoryControllerTest {
}
@Test
public void isUnavailable_whenHardwareNotDetected() {
@EnableFlags(android.hardware.biometrics.Flags.FLAG_SCREEN_OFF_UNLOCK_UDFPS)
public void isUnavailable_isDisabled_whenUdfpsHardwareDetected_AndNoEnrolledFingerprints() {
assertThat(mScreenOffUnlockController.isAvailable()).isEqualTo(false);
assertThat(mScreenOffUnlockController.getAvailabilityStatus()).isEqualTo(
UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
false /* isPowerbuttonFps false implies udfps */,
false /* hasEnrolledTemplates */);
assertThat(mScreenOffUnlockController.isAvailable()).isEqualTo(false);
assertThat(mScreenOffUnlockController.getAvailabilityStatus()).isEqualTo(
CONDITIONALLY_UNAVAILABLE);
}
@Test
public void isUnavailable_whenHardwareNotDetected_onSfpsDevice() {
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
@@ -113,6 +154,21 @@ public class FingerprintSettingsUnlockCategoryControllerTest {
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
@EnableFlags(android.hardware.biometrics.Flags.FLAG_SCREEN_OFF_UNLOCK_UDFPS)
public void isUnavailable_whenHardwareNotDetected_onUdfpsDevice() {
assertThat(mScreenOffUnlockController.isAvailable()).isFalse();
assertThat(mScreenOffUnlockController.getAvailabilityStatus()).isEqualTo(
UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
false /* isHardwareDetected */,
false /* isPowerbuttonFps false implies udfps */,
true /* hasEnrolledTemplates */);
assertThat(mScreenOffUnlockController.isAvailable()).isEqualTo(false);
assertThat(mScreenOffUnlockController.getAvailabilityStatus()).isEqualTo(
UNSUPPORTED_ON_DEVICE);
}
@Test
public void isUnavailable_onNonSfpsDevice() {
assertThat(mController.isAvailable()).isFalse();

View File

@@ -0,0 +1,58 @@
/*
* 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.deviceinfo.aboutphone
import android.content.Context
import android.os.Build
import android.provider.Settings.Global
import com.android.settings.flags.Flags
import com.android.settingslib.preference.CatalystScreenTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.robolectric.RuntimeEnvironment
class MyDeviceInfoScreenTest : CatalystScreenTestCase() {
private lateinit var context: Context
override val preferenceScreenCreator = MyDeviceInfoScreen()
override val flagName: String
get() = Flags.FLAG_CATALYST_MY_DEVICE_INFO_PREF_SCREEN
override fun migration() {}
@Before
fun setup() {
context = RuntimeEnvironment.getApplication()
}
@Test
fun key() {
assertThat(preferenceScreenCreator.key).isEqualTo(MyDeviceInfoScreen.KEY)
}
@Test
fun getSummary_deviceNameNotSet_shouldReturnDeviceModel() {
assertThat(preferenceScreenCreator.getSummary(context)?.toString()).isEqualTo(Build.MODEL)
}
@Test
fun getSummary_deviceNameSet_shouldReturnDeviceName() {
Global.putString(context.contentResolver, Global.DEVICE_NAME, "Test")
assertThat(preferenceScreenCreator.getSummary(context)?.toString()).isEqualTo("Test")
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network
import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.res.Resources
import androidx.test.core.app.ApplicationProvider
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.ArgumentMatchers.anyInt
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class AirplaneModePreferenceTest {
private val mockPackageManager = mock<PackageManager>()
private val mockResources = mock<Resources>()
private val context =
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
override fun getPackageManager(): PackageManager = mockPackageManager
override fun getResources(): Resources = mockResources
}
private val airplaneModePreference = AirplaneModePreference()
@Test
fun isAvailable_hasConfigAndNoFeatureLeanback_shouldReturnTrue() {
mockResources.stub { on { getBoolean(anyInt()) } doReturn true }
mockPackageManager.stub { on { hasSystemFeature(FEATURE_LEANBACK) } doReturn false }
assertThat(airplaneModePreference.isAvailable(context)).isTrue()
}
@Test
fun isAvailable_noConfig_shouldReturnFalse() {
mockResources.stub { on { getBoolean(anyInt()) } doReturn false }
mockPackageManager.stub { on { hasSystemFeature(FEATURE_LEANBACK) } doReturn false }
assertThat(airplaneModePreference.isAvailable(context)).isFalse()
}
@Test
fun isAvailable_hasFeatureLeanback_shouldReturnFalse() {
mockResources.stub { on { getBoolean(anyInt()) } doReturn true }
mockPackageManager.stub { on { hasSystemFeature(FEATURE_LEANBACK) } doReturn true }
assertThat(airplaneModePreference.isAvailable(context)).isFalse()
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network.tether
import android.net.TetheringManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settings.flags.Flags
import com.android.settings.testutils.shadow.ShadowConnectivityManager
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal
import com.android.settingslib.Utils
import com.android.settingslib.preference.CatalystScreenTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
import org.robolectric.annotation.Implementation
import org.robolectric.annotation.Implements
@RunWith(AndroidJUnit4::class)
@Config(shadows = [ShadowConnectivityManager::class, ShadowRestrictedLockUtilsInternal::class,
ShadowTetheringManager::class])
class TetherScreenTest : CatalystScreenTestCase() {
override val preferenceScreenCreator = TetherScreen()
override val flagName: String
get() = Flags.FLAG_CATALYST_TETHER_SETTINGS
@Before
fun setUp() {
ShadowConnectivityManager.getShadow().setTetheringSupported(true)
}
@Test
fun key() {
assertThat(preferenceScreenCreator.key).isEqualTo(TetherScreen.KEY)
}
@Test
fun getPreferenceTitle_tetherConfigDisallowed_shouldShowAll() {
ShadowRestrictedLockUtilsInternal.setRestricted(true)
assertThat(preferenceScreenCreator.getPreferenceTitle(appContext)).isEqualTo(
appContext.getString(R.string.tether_settings_title_all))
}
@Test
fun getPreferenceTitle_tetherConfigAllowed_shouldShowTetheringLabel() {
ShadowRestrictedLockUtilsInternal.setRestricted(false)
val tm = appContext.getSystemService(TetheringManager::class.java)
assertThat(preferenceScreenCreator.getPreferenceTitle(appContext)).isEqualTo(
appContext.getText(Utils.getTetheringLabel(tm)))
}
@Test
fun isAvailable_tetherIsAvailable_shouldReturnTrue() {
ShadowRestrictedLockUtilsInternal.setRestricted(false)
assertThat(preferenceScreenCreator.isAvailable(appContext)).isTrue()
}
@Test
fun isAvailable_tetherIsUnavailable_shouldReturnFalse() {
ShadowRestrictedLockUtilsInternal.setRestricted(true)
assertThat(preferenceScreenCreator.isAvailable(appContext)).isFalse()
}
}
@Implements(TetheringManager::class)
class ShadowTetheringManager {
private val emptyArray = arrayOf<String>()
@Implementation
fun getTetheredIfaces() = emptyArray
@Implementation
fun getTetherableIfaces() = emptyArray
@Implementation
fun getTetherableWifiRegexs() = emptyArray
@Implementation
fun getTetherableUsbRegexs() = emptyArray
@Implementation
fun getTetherableBluetoothRegexs() = emptyArray
}

View File

@@ -58,6 +58,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
// LINT.IfChange
@RunWith(RobolectricTestRunner.class)
@Config(shadows = MediaVolumePreferenceControllerTest.ShadowSliceBackgroundWorker.class)
public class MediaVolumePreferenceControllerTest {
@@ -269,3 +270,4 @@ public class MediaVolumePreferenceControllerTest {
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
}
// LINT.ThenChange(MediaVolumePreference.kt)

View File

@@ -0,0 +1,56 @@
/*
* 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.notification
import android.content.ContextWrapper
import android.content.res.Resources
import androidx.test.core.app.ApplicationProvider
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.ArgumentMatchers.anyInt
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub
// LINT.IfChange
@RunWith(AndroidJUnit4::class)
class MediaVolumePreferenceTest {
private val mockResources = mock<Resources>()
private val mediaVolumePreference = MediaVolumePreference()
private val context =
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
override fun getResources(): Resources = mockResources
}
@Test
fun isAvailable_configTrue_shouldReturnTrue() {
mockResources.stub { on { getBoolean(anyInt()) } doReturn true }
assertThat(mediaVolumePreference.isAvailable(context)).isTrue()
}
@Test
fun isAvailable_configFalse_shouldReturnFalse() {
mockResources.stub { on { getBoolean(anyInt()) } doReturn false }
assertThat(mediaVolumePreference.isAvailable(context)).isFalse()
}
}
// LINT.ThenChange(MediaVolumePreferenceControllerTest.java)

View File

@@ -41,6 +41,7 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
// LINT.IfChange
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowDeviceConfig.class})
public class SeparateRingVolumePreferenceControllerTest {
@@ -108,3 +109,4 @@ public class SeparateRingVolumePreferenceControllerTest {
}
}
// LINT.ThenChange(SeparateRingVolumePreferenceTest.kt)

View File

@@ -0,0 +1,150 @@
/*
* 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.notification
import android.content.ContextWrapper
import android.media.AudioManager.RINGER_MODE_NORMAL
import android.media.AudioManager.RINGER_MODE_SILENT
import android.media.AudioManager.RINGER_MODE_VIBRATE
import android.os.Vibrator
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.google.common.truth.Truth.assertThat
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
// LINT.IfChange
@RunWith(AndroidJUnit4::class)
class SeparateRingVolumePreferenceTest {
private var audioHelper = mock<AudioHelper>()
private var vibrator: Vibrator? = null
private var ringVolumePreference = SeparateRingVolumePreference()
private val context =
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
override fun getSystemService(name: String): Any? =
when {
name == getSystemServiceName(Vibrator::class.java) -> vibrator
else -> super.getSystemService(name)
}
}
@Test
fun isAvailable_singleVolume_shouldReturnFalse() {
audioHelper = mock { on { isSingleVolume } doReturn true }
ringVolumePreference =
spy(ringVolumePreference).stub {
onGeneric { createAudioHelper(context) } doReturn audioHelper
}
assertThat(ringVolumePreference.isAvailable(context)).isFalse()
}
@Test
fun isAvailable_noSingleVolume_shouldReturnTrue() {
audioHelper = mock { on { isSingleVolume } doReturn false }
ringVolumePreference =
spy(ringVolumePreference).stub {
onGeneric { createAudioHelper(context) } doReturn audioHelper
}
assertThat(ringVolumePreference.isAvailable(context)).isTrue()
}
@Test
fun getEffectiveRingerMode_noVibratorAndVibrateMode_shouldReturnSilentMode() {
vibrator = mock { on { hasVibrator() } doReturn false }
audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_VIBRATE }
ringVolumePreference =
spy(ringVolumePreference).stub {
onGeneric { createAudioHelper(context) } doReturn audioHelper
}
assertThat(ringVolumePreference.getEffectiveRingerMode(context))
.isEqualTo(RINGER_MODE_SILENT)
}
@Test
fun getEffectiveRingerMode_hasVibratorAndVibrateMode_shouldReturnVibrateMode() {
vibrator = mock { on { hasVibrator() } doReturn true }
audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_VIBRATE }
ringVolumePreference =
spy(ringVolumePreference).stub {
onGeneric { createAudioHelper(context) } doReturn audioHelper
}
assertThat(ringVolumePreference.getEffectiveRingerMode(context))
.isEqualTo(RINGER_MODE_VIBRATE)
}
@Test
fun getEffectiveRingerMode_hasVibratorAndNormalMode_shouldReturnNormalMode() {
vibrator = mock { on { hasVibrator() } doReturn true }
audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_NORMAL }
ringVolumePreference =
spy(ringVolumePreference).stub {
onGeneric { createAudioHelper(context) } doReturn audioHelper
}
assertThat(ringVolumePreference.getEffectiveRingerMode(context))
.isEqualTo(RINGER_MODE_NORMAL)
}
@Test
fun getMuteIcon_normalMode_shouldReturnRingVolumeIcon() {
vibrator = mock { on { hasVibrator() } doReturn true }
audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_NORMAL }
ringVolumePreference =
spy(ringVolumePreference).stub {
onGeneric { createAudioHelper(context) } doReturn audioHelper
}
assertThat(ringVolumePreference.getMuteIcon(context)).isEqualTo(R.drawable.ic_ring_volume)
}
@Test
fun getMuteIcon_vibrateMode_shouldReturnVibrateIcon() {
vibrator = mock { on { hasVibrator() } doReturn true }
audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_VIBRATE }
ringVolumePreference =
spy(ringVolumePreference).stub {
onGeneric { createAudioHelper(context) } doReturn audioHelper
}
assertThat(ringVolumePreference.getMuteIcon(context))
.isEqualTo(R.drawable.ic_volume_ringer_vibrate)
}
@Test
fun getMuteIcon_silentMode_shouldReturnSilentIcon() {
vibrator = mock { on { hasVibrator() } doReturn false }
audioHelper = mock { on { ringerModeInternal } doReturn RINGER_MODE_VIBRATE }
ringVolumePreference =
spy(ringVolumePreference).stub {
onGeneric { createAudioHelper(context) } doReturn audioHelper
}
assertThat(ringVolumePreference.getMuteIcon(context))
.isEqualTo(R.drawable.ic_ring_volume_off)
}
}
// LINT.ThenChange(SeparateRingVolumePreferenceControllerTest.java)

View File

@@ -34,7 +34,6 @@ import android.net.VpnManager;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.SettingsSlicesContract;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
@@ -102,7 +101,7 @@ public class VpnPreferenceControllerTest {
controller.displayPreference(mScreen);
verify(mPreference).setDependency(SettingsSlicesContract.KEY_AIRPLANE_MODE);
verify(mPreference).setDependency(Settings.Global.AIRPLANE_MODE_ON);
}
@Test