Snap for 12587146 from 2977bc7825
to 25Q1-release
Change-Id: Iafb0e27e4472861e6dde58785800d1141e11274a
This commit is contained in:
@@ -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",
|
||||
|
@@ -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"
|
||||
|
@@ -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"
|
||||
}
|
||||
|
@@ -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"
|
||||
|
@@ -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] -->
|
||||
|
@@ -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"/>
|
||||
|
@@ -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"
|
||||
|
@@ -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
|
||||
|
@@ -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() {
|
||||
|
@@ -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 {}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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());
|
||||
|
@@ -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() {
|
||||
|
@@ -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() {};
|
||||
|
||||
}
|
@@ -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 {
|
||||
|
@@ -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(),
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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"
|
||||
}
|
||||
}
|
@@ -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)
|
||||
|
@@ -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)
|
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
42
src/com/android/settings/network/AirplaneModePreference.kt
Normal file
42
src/com/android/settings/network/AirplaneModePreference.kt
Normal 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)
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
63
src/com/android/settings/network/tether/TetherScreen.kt
Normal file
63
src/com/android/settings/network/tether/TetherScreen.kt
Normal 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"
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
118
src/com/android/settings/notification/MediaVolumePreference.kt
Normal file
118
src/com/android/settings/notification/MediaVolumePreference.kt
Normal 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)
|
@@ -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)
|
||||
|
@@ -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)
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
|
62
src/com/android/settings/notification/VolumeHelper.kt
Normal file
62
src/com/android/settings/notification/VolumeHelper.kt
Normal 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
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
34
src/com/android/settings/utils/IntentUtils.kt
Normal file
34
src/com/android/settings/utils/IntentUtils.kt
Normal 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)
|
||||
}
|
@@ -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;
|
||||
|
@@ -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() {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
|
@@ -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")
|
||||
}
|
||||
}
|
@@ -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()
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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)
|
||||
|
@@ -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)
|
@@ -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)
|
||||
|
@@ -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)
|
@@ -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
|
||||
|
Reference in New Issue
Block a user