Snap for 12616459 from 9d1515e3ca to 25Q1-release

Change-Id: Id11744dba6165ba9da196e11833373c8c6f574f3
This commit is contained in:
Android Build Coastguard Worker
2024-11-07 00:25:22 +00:00
40 changed files with 1111 additions and 159 deletions

View File

@@ -1567,7 +1567,7 @@
<item>@*android:drawable/ic_zen_mode_icon_child</item>
<item>@*android:drawable/ic_zen_mode_icon_animal_paw</item>
<!-- Generic / abstract -->
<item>@*android:drawable/ic_zen_mode_type_unknown</item> <!-- Star badge -->
<item>@*android:drawable/ic_zen_mode_icon_star_badge</item>
<item>@*android:drawable/ic_zen_mode_type_managed</item> <!-- Two people / Supervisor -->
<item>@*android:drawable/ic_zen_mode_type_other</item> <!-- Star -->
<item>@*android:drawable/ic_zen_mode_icon_heart</item>

View File

@@ -9041,6 +9041,13 @@
<string name="notification_polite_work">Apply to work profiles</string>
<string name="notification_polite_work_summary">Apply to work profile apps</string>
<!-- Title for Bundled Notifications setting [CHAR LIMIT=45]-->
<string name="notification_bundle_title">Bundled notifications</string>
<string name="notification_bundle_on">On</string>
<string name="notification_bundle_off">Off</string>
<string name="notification_bundle_main_control_title">Use notification bundling</string>
<string name="notification_bundle_description">Notifications with similar themes will be silenced and grouped together for a quieter experience. Bundling will override an app\'s own notification settings.</string>
<!-- Title for managing VR (virtual reality) helper services. [CHAR LIMIT=50] -->
<string name="vr_listeners_title">VR helper services</string>
@@ -13781,9 +13788,12 @@
<string name="contacts_storage_no_account_set_summary">No default set</string>
<!-- Text for displaying when default account is set as local only [CHAR LIMIT=50] -->
<string name="contacts_storage_local_account_summary">Device only</string>
<!-- Text for displaying eligible account preference title [CHAR LIMIT=50] -->
<string name="contacts_storage_account_title">Device and %1$s</string>
<!-- Text for add account selection message when no account has been added [CHAR LIMIT=100] -->
<string name="contacts_storage_first_time_add_account_message">Add an account to get started</string>
<!-- Text for account preference category title for contacts storage settings page [CHAR LIMIT=100] -->
<string name="contacts_storage_account_category_title">Where to save contacts</string>
<!-- Circle to Search (shared between all entrypoints) -->
<!-- Name of Google's new feature to circle to search anything on your phone screen,
without switching apps. Also used as the setting title. [CHAR LIMIT=60] -->

View File

@@ -20,7 +20,8 @@
android:title="@string/accessibility_hearingaid_title">
<com.android.settingslib.widget.TopIntroPreference
android:title="@string/accessibility_hearingaid_intro" />
android:title="@string/accessibility_hearingaid_intro"
settings:searchable="false" />
<PreferenceCategory
android:key="available_hearing_devices"

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/notification_bundle_title">
<com.android.settingslib.widget.IllustrationPreference
android:key="illustration"
settings:searchable="false"
android:selectable="false"
app:lottie_cacheComposition="false"
settings:dynamicColor="true"/>
<com.android.settingslib.widget.TopIntroPreference
android:key="feature_description"
settings:searchable="false"
android:title="@string/notification_bundle_description"/>
<com.android.settingslib.widget.MainSwitchPreference
android:key="global_pref"
android:title="@string/notification_bundle_main_control_title"
settings:controller="com.android.settings.notification.BundleGlobalPreferenceController" />
<CheckBoxPreference
android:key="promotions"
android:title="@*android:string/promotional_notification_channel_label"
settings:controller="com.android.settings.notification.BundleTypePreferenceController"/>
<CheckBoxPreference
android:key="news"
android:title="@*android:string/news_notification_channel_label"
settings:controller="com.android.settings.notification.BundleTypePreferenceController"/>
<CheckBoxPreference
android:key="social"
android:title="@*android:string/social_notification_channel_label"
settings:controller="com.android.settings.notification.BundleTypePreferenceController"/>
<CheckBoxPreference
android:key="recs"
android:title="@*android:string/recs_notification_channel_label"
settings:controller="com.android.settings.notification.BundleTypePreferenceController"/>
</PreferenceScreen>

View File

@@ -43,6 +43,14 @@
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.notification.history.NotificationHistoryActivity" />
</Preference>
<Preference
android:fragment="com.android.settings.notification.BundlePreferenceFragment"
android:key="bundle_notifications_preference"
android:persistent="false"
android:order="12"
android:title="@string/notification_bundle_title"
settings:controller="com.android.settings.notification.BundlePreferenceController" />
</PreferenceCategory>
<PreferenceCategory

View File

@@ -22,6 +22,12 @@
<com.android.settingslib.widget.TopIntroPreference
android:title="@string/contacts_storage_selection_message" />
<PreferenceCategory
android:key="account_category"
android:persistent="false"
android:title="@string/contacts_storage_account_category_title">
</PreferenceCategory>
<com.android.settingslib.widget.SelectorWithWidgetPreference
android:key="device_only_account_preference"
android:summary="@string/contacts_storage_device_only_preference_summary"

View File

@@ -27,11 +27,6 @@
settings:controller="com.android.settings.dream.DreamMainSwitchPreferenceController"
settings:searchable="false"/>
<Preference
android:key="when_to_start"
android:title="@string/screensaver_settings_when_to_dream"
android:fragment="com.android.settings.dream.WhenToDreamPicker"/>
<PreferenceCategory
android:title="@string/dream_picker_category">
<com.android.settingslib.widget.LayoutPreference
@@ -40,6 +35,11 @@
android:layout="@layout/dream_picker_layout"/>
</PreferenceCategory>
<Preference
android:key="when_to_start"
android:title="@string/screensaver_settings_when_to_dream"
android:fragment="com.android.settings.dream.WhenToDreamPicker"/>
<SwitchPreferenceCompat
android:key="dream_complications_toggle"
android:title="@string/dream_complications_toggle_title"

View File

@@ -0,0 +1,44 @@
/*
* 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
import android.content.Context
import android.os.UserHandle
import androidx.annotation.CallSuper
import com.android.settingslib.RestrictedLockUtilsInternal
import com.android.settingslib.metadata.PreferenceRestrictionProvider
/** Mixin to support restriction. */
interface PreferenceRestrictionMixin : PreferenceRestrictionProvider {
val restrictionKey: String
val useAdminDisabledSummary: Boolean
get() = false
@CallSuper fun isEnabled(context: Context) = !context.hasBaseUserRestriction(restrictionKey)
override fun isRestricted(context: Context) =
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context,
restrictionKey,
UserHandle.myUserId(),
) != null
}
fun Context.hasBaseUserRestriction(restrictionKey: String) =
RestrictedLockUtilsInternal.hasBaseUserRestriction(this, restrictionKey, UserHandle.myUserId())

View File

@@ -33,6 +33,7 @@ import android.widget.CheckedTextView;
import android.widget.ListAdapter;
import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AlertDialog.Builder;
import androidx.preference.ListPreferenceDialogFragmentCompat;
@@ -40,11 +41,14 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreferenceHelper;
import com.android.settingslib.RestrictedPreferenceHelperProvider;
import java.util.ArrayList;
import java.util.List;
public class RestrictedListPreference extends CustomListPreference {
public class RestrictedListPreference extends CustomListPreference implements
RestrictedPreferenceHelperProvider {
private final RestrictedPreferenceHelper mHelper;
private final List<RestrictedItem> mRestrictedItems = new ArrayList<>();
private boolean mRequiresActiveUnlockedProfile = false;
@@ -61,6 +65,11 @@ public class RestrictedListPreference extends CustomListPreference {
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
}
@Override
public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() {
return mHelper;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);

View File

@@ -46,6 +46,7 @@ import com.android.settingslib.datastore.BackupRestoreStorageManager;
import com.android.settingslib.metadata.PreferenceScreenMetadata;
import com.android.settingslib.metadata.PreferenceScreenRegistry;
import com.android.settingslib.metadata.ProvidePreferenceScreenOptions;
import com.android.settingslib.preference.PreferenceBindingFactory;
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory;
import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -76,6 +77,7 @@ public class SettingsApplication extends Application {
if (Flags.catalyst()) {
PreferenceScreenRegistry.INSTANCE.setPreferenceScreensSupplier(
this::getPreferenceScreens);
PreferenceBindingFactory.setDefaultFactory(new SettingsPreferenceBindingFactory());
}
BackupRestoreStorageManager.getInstance(this)

View File

@@ -0,0 +1,49 @@
/*
* 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
import android.os.UserHandle
import androidx.preference.Preference
import com.android.settingslib.RestrictedPreferenceHelperProvider
import com.android.settingslib.metadata.PreferenceHierarchyNode
import com.android.settingslib.preference.DefaultPreferenceBindingFactory
import com.android.settingslib.preference.PreferenceBinding
/** Preference binding factory for settings app. */
class SettingsPreferenceBindingFactory : DefaultPreferenceBindingFactory() {
override fun bind(
preference: Preference,
node: PreferenceHierarchyNode,
preferenceBinding: PreferenceBinding?,
) {
super.bind(preference, node, preferenceBinding)
// handle restriction consistently
val metadata = node.metadata
if (metadata is PreferenceRestrictionMixin) {
if (preference is RestrictedPreferenceHelperProvider) {
preference.getRestrictedPreferenceHelper().apply {
val restrictionKey = metadata.restrictionKey
if (!preference.context.hasBaseUserRestriction(restrictionKey)) {
useAdminDisabledSummary(metadata.useAdminDisabledSummary)
checkRestrictionAndSetDisabled(restrictionKey, UserHandle.myUserId())
}
}
}
}
}
}

View File

@@ -61,6 +61,9 @@ public class ContactsStoragePreferenceController extends BasePreferenceControlle
@Override
public CharSequence getSummary() {
if (mCurrentDefaultAccountAndState != null) {
// Re-fetch account in controller to refresh the latest set default account.
mCurrentDefaultAccountAndState =
DefaultAccount.getDefaultAccountForNewContacts(mContext.getContentResolver());
int currentDefaultAccountState = mCurrentDefaultAccountAndState.getState();
Account currentDefaultAccount = mCurrentDefaultAccountAndState.getAccount();
if (currentDefaultAccountState

View File

@@ -25,6 +25,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
@@ -36,7 +37,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceClickListener;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceGroup;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
@@ -63,6 +64,7 @@ public class ContactsStorageSettings extends DashboardFragment
private static final String TAG = "ContactsStorageSettings";
private static final String PREF_KEY_ADD_ACCOUNT = "add_account";
private static final String PREF_KEY_DEVICE_ONLY = "device_only_account_preference";
private static final String PREF_KEY_ACCOUNT_CATEGORY = "account_category";
private final Map<String, DefaultAccountAndState> mAccountMap = new HashMap<>();
private AuthenticatorHelper mAuthenticatorHelper;
@@ -71,6 +73,12 @@ public class ContactsStorageSettings extends DashboardFragment
super.onAttach(context);
mAuthenticatorHelper = new AuthenticatorHelper(context,
new UserHandle(UserHandle.myUserId()), null);
String[] accountTypes = getEligibleAccountTypes();
for (String accountType : accountTypes) {
// Preload the drawable for the account type to avoid the latency when rendering the
// account preference.
mAuthenticatorHelper.preloadDrawableForType(context, accountType);
}
}
@UiThread
@@ -130,23 +138,24 @@ public class ContactsStorageSettings extends DashboardFragment
// Clear all the accounts stored in the map and later on re-fetch the eligible accounts
// when creating eligible account preferences.
mAccountMap.clear();
final PreferenceScreen screen = getPreferenceScreen();
final PreferenceGroup preferenceGroup = findPreference(PREF_KEY_ACCOUNT_CATEGORY);
// If the default account is SIM, we should show in the page, otherwise don't show.
SelectorWithWidgetPreference simAccountPreference = buildSimAccountPreference();
if (simAccountPreference != null) {
getPreferenceScreen().addPreference(simAccountPreference);
preferenceGroup.addPreference(simAccountPreference);
}
List<Account> accounts = DefaultAccount.getEligibleCloudAccounts(getContentResolver());
for (int i = 0; i < accounts.size(); i++) {
screen.addPreference(buildCloudAccountPreference(accounts.get(i), /*order=*/i));
preferenceGroup.addPreference(
buildCloudAccountPreference(accounts.get(i), /*order=*/i));
}
// If there's no eligible account types, the "Add Account" preference should
// not be shown to the users.
if (getEligibleAccountTypes().length > 0) {
screen.addPreference(buildAddAccountPreference(accounts.isEmpty()));
getPreferenceScreen().addPreference(buildAddAccountPreference(accounts.isEmpty()));
}
setupDeviceOnlyPreference();
setDefaultAccountPreference();
setDefaultAccountPreference(preferenceGroup);
}
private void setupDeviceOnlyPreference() {
@@ -157,7 +166,7 @@ public class ContactsStorageSettings extends DashboardFragment
}
}
private void setDefaultAccountPreference() {
private void setDefaultAccountPreference(PreferenceGroup preferenceGroup) {
DefaultAccountAndState currentDefaultAccountAndState =
DefaultAccount.getDefaultAccountForNewContacts(getContentResolver());
String preferenceKey = getAccountHashCode(currentDefaultAccountAndState);
@@ -170,20 +179,21 @@ public class ContactsStorageSettings extends DashboardFragment
preference = getPreferenceScreen().findPreference(preferenceKey);
} else if (preferenceKey != null && currentDefaultAccount != null) {
preference = buildCloudAccountPreference(currentDefaultAccount, mAccountMap.size());
getPreferenceScreen().addPreference(preference);
preferenceGroup.addPreference(preference);
}
if (preference != null) {
preference.setChecked(true);
}
}
//TODO: Add preference category on account preferences.
private SelectorWithWidgetPreference buildCloudAccountPreference(Account account, int order) {
SelectorWithWidgetPreference preference = new SelectorWithWidgetPreference(
getPrefContext());
DefaultAccountAndState accountAndState = DefaultAccountAndState.ofCloud(account);
String preferenceKey = getAccountHashCode(accountAndState);
preference.setTitle(mAuthenticatorHelper.getLabelForType(getPrefContext(), account.type));
String accountPreferenceTitle = getString(R.string.contacts_storage_account_title,
mAuthenticatorHelper.getLabelForType(getPrefContext(), account.type));
preference.setTitle(accountPreferenceTitle);
preference.setIcon(mAuthenticatorHelper.getDrawableForType(getPrefContext(), account.type));
preference.setSummary(account.name);
preference.setKey(preferenceKey);

View File

@@ -16,6 +16,7 @@
package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT
import android.view.accessibility.AccessibilityManager
@@ -30,23 +31,26 @@ import kotlinx.coroutines.flow.stateIn
interface AccessibilityInteractor {
/** A flow that contains whether or not accessibility is enabled */
fun isEnabledFlow(scope: CoroutineScope): Flow<Boolean>
val isEnabled: Boolean
fun announce(clazz: Class<*>, announcement: CharSequence?)
fun interrupt()
}
class AccessibilityInteractorImpl(
private val accessibilityManager: AccessibilityManager,
) : AccessibilityInteractor {
class AccessibilityInteractorImpl(private val accessibilityManager: AccessibilityManager) :
AccessibilityInteractor {
/** A flow that contains whether or not accessibility is enabled */
override fun isEnabledFlow(scope: CoroutineScope): Flow<Boolean> =
callbackFlow {
val listener =
AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) }
accessibilityManager.addAccessibilityStateChangeListener(listener)
val listener =
AccessibilityManager.AccessibilityStateChangeListener { enabled -> trySend(enabled) }
accessibilityManager.addAccessibilityStateChangeListener(listener)
// This clause will be called when no one is listening to the flow
awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) }
}
// This clause will be called when no one is listening to the flow
awaitClose { accessibilityManager.removeAccessibilityStateChangeListener(listener) }
}
.stateIn(
scope,
SharingStarted.WhileSubscribed(), // When no longer subscribed, we removeTheListener
@@ -63,4 +67,17 @@ class AccessibilityInteractorImpl(
event.text.add(announcement)
accessibilityManager.sendAccessibilityEvent(event)
}
/** Interrupts the current accessibility manager from announcing a phrase. */
override fun interrupt() {
try {
accessibilityManager.interrupt()
} catch (e: IllegalStateException) {
Log.e(TAG, "Error trying to interrupt when accessibility isn't enabled $e")
}
}
companion object {
const val TAG = "AccessibilityInteractor"
}
}

View File

@@ -19,10 +19,13 @@ package com.android.settings.biometrics.fingerprint2.domain.interactor
import android.content.Context
import android.view.OrientationEventListener
import com.android.internal.R
import com.android.settings.biometrics.fingerprint2.lib.model.Orientation
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.transform
/** Interactor which provides information about orientation */
@@ -45,6 +48,9 @@ interface OrientationInteractor {
* [R.bool.config_reverseDefaultConfigRotation]
*/
fun getRotationFromDefault(rotation: Int): Int
/** Indicates an orientation changed event has occurred */
val orientationChanged: Flow<Orientation>
}
class OrientationInteractorImpl(private val context: Context) : OrientationInteractor {
@@ -60,7 +66,10 @@ class OrientationInteractorImpl(private val context: Context) : OrientationInter
awaitClose { orientationEventListener.disable() }
}
override val rotation: Flow<Int> = orientation.transform { emit(context.display.rotation) }
override val rotation: Flow<Int> =
orientation
.transform { emit(context.display.rotation) }
.onStart { emit(context.display.rotation) }
override val rotationFromDefault: Flow<Int> = rotation.map { getRotationFromDefault(it) }
@@ -73,4 +82,24 @@ class OrientationInteractorImpl(private val context: Context) : OrientationInter
rotation
}
}
override val orientationChanged: Flow<Orientation> =
rotationFromDefault
.map {
when (it) {
1 -> {
Orientation.Portrait
}
2 -> {
Orientation.ReverseLandscape
}
3 -> {
Orientation.UpsideDownPortrait
}
else -> {
Orientation.Landscape
}
}
}
.distinctUntilChanged()
}

View File

@@ -0,0 +1,32 @@
/*
* 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.fingerprint2.lib.model
/** The orientation events correspond to androids internal orientation events. */
sealed class Orientation {
/** Indicates the device is in landscape orientation */
data object Landscape : Orientation()
/** Indicates the device is in reverse landscape orientation */
data object ReverseLandscape : Orientation()
/** Indicates the device is in portrait orientation */
data object Portrait : Orientation()
/** Indicates the device is in the upside down portrait orientation */
data object UpsideDownPortrait : Orientation()
}

View File

@@ -294,6 +294,7 @@ class DeviceDetailsFragmentFormatterImpl(
TwoTargetSwitchPreference(
switchPrefModel,
primaryOnClick = { triggerAction(model.action) },
primaryEnabled = { !model.disabled }
)
} else {
SwitchPreference(switchPrefModel)

View File

@@ -30,6 +30,7 @@ import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedPreferenceHelper;
import com.android.settingslib.RestrictedPreferenceHelperProvider;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -37,7 +38,7 @@ import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.AppSwitchPreference;
public class UnrestrictedDataAccessPreference extends AppSwitchPreference implements
DataSaverBackend.Listener {
DataSaverBackend.Listener, RestrictedPreferenceHelperProvider {
private static final String ECM_SETTING_IDENTIFIER = "android:unrestricted_data_access";
private final ApplicationsState mApplicationsState;
@@ -78,6 +79,11 @@ public class UnrestrictedDataAccessPreference extends AppSwitchPreference implem
return entry.info.packageName + "|" + entry.info.uid;
}
@Override
public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() {
return mHelper;
}
@Override
public void onAttached() {
super.onAttached();

View File

@@ -16,17 +16,15 @@
package com.android.settings.display
import android.content.Context
import android.os.Process
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
import android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
import android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL
import androidx.preference.Preference
import com.android.settings.PreferenceRestrictionMixin
import com.android.settings.R
import com.android.settings.flags.Flags
import com.android.settingslib.PrimarySwitchPreference
import com.android.settingslib.RestrictedLockUtilsInternal
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyedObservableDelegate
import com.android.settingslib.datastore.SettingsStore
@@ -35,7 +33,6 @@ import com.android.settingslib.metadata.BooleanValue
import com.android.settingslib.metadata.PersistentPreference
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.PreferenceRestrictionProvider
import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.metadata.preferenceHierarchy
@@ -47,7 +44,7 @@ class AutoBrightnessScreen :
PreferenceScreenCreator,
PreferenceScreenBinding,
PreferenceAvailabilityProvider,
PreferenceRestrictionProvider,
PreferenceRestrictionMixin,
PersistentPreference<Boolean>,
BooleanValue {
override val key: String
@@ -75,23 +72,19 @@ class AutoBrightnessScreen :
com.android.internal.R.bool.config_automatic_brightness_available
)
override fun isEnabled(context: Context) =
!UserManager.get(context)
.hasBaseUserRestriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, Process.myUserHandle())
override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
override fun isRestricted(context: Context) =
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context,
UserManager.DISALLOW_CONFIG_BRIGHTNESS,
UserHandle.myUserId(),
) != null
override val restrictionKey: String
get() = UserManager.DISALLOW_CONFIG_BRIGHTNESS
override val useAdminDisabledSummary: Boolean
get() = true
override fun createWidget(context: Context) = PrimarySwitchPreference(context)
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
super.bind(preference, metadata)
(preference as PrimarySwitchPreference).apply {
useAdminDisabledSummary(true)
isSwitchEnabled = isEnabled
// "true" is not the real default value (it is provided by AutoBrightnessDataStore)
isChecked = preferenceDataStore!!.getBoolean(key, true)

View File

@@ -23,15 +23,13 @@ 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.PreferenceRestrictionMixin
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
@@ -42,7 +40,6 @@ 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
@@ -52,7 +49,7 @@ import java.text.NumberFormat
class BrightnessLevelRestrictedPreference :
PreferenceMetadata,
PreferenceBinding,
PreferenceRestrictionProvider,
PreferenceRestrictionMixin,
PreferenceSummaryProvider,
PreferenceLifecycleProvider,
Preference.OnPreferenceClickListener {
@@ -69,34 +66,28 @@ class BrightnessLevelRestrictedPreference :
override val keywords: Int
get() = R.string.keywords_display_brightness_level
override fun getSummary(context: Context) =
override fun getSummary(context: Context): CharSequence? =
NumberFormat.getPercentInstance().format(getCurrentBrightness(context))
override fun isEnabled(context: Context) =
!UserManager.get(context)
.hasBaseUserRestriction(UserManager.DISALLOW_CONFIG_BRIGHTNESS, Process.myUserHandle())
override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
override fun isRestricted(context: Context) =
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context,
UserManager.DISALLOW_CONFIG_BRIGHTNESS,
UserHandle.myUserId(),
) != null
override val restrictionKey: String
get() = UserManager.DISALLOW_CONFIG_BRIGHTNESS
override val useAdminDisabledSummary: Boolean
get() = true
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)
}
KeyedObserver<String> { _, _ ->
context.notifyPreferenceChange(this@BrightnessLevelRestrictedPreference)
}
brightnessObserver = observer
SettingsSystemStore.get(context)
@@ -113,13 +104,11 @@ class BrightnessLevelRestrictedPreference :
}
}
displayListener = listener
context
.getSystemService(DisplayManager::class.java)
.registerDisplayListener(
listener,
HandlerExecutor.main,
DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS,
)
context.displayManager.registerDisplayListener(
listener,
HandlerExecutor.main,
DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS,
)
}
override fun onStop(context: PreferenceLifecycleContext) {
@@ -129,11 +118,14 @@ class BrightnessLevelRestrictedPreference :
}
displayListener?.let {
context.getSystemService(DisplayManager::class.java).unregisterDisplayListener(it)
context.displayManager.unregisterDisplayListener(it)
displayListener = null
}
}
private val Context.displayManager: DisplayManager
get() = getSystemService(DisplayManager::class.java)!!
override fun onPreferenceClick(preference: Preference): Boolean {
val context = preference.context
val intent =

View File

@@ -0,0 +1,61 @@
/*
* 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.Flags;
import android.content.Context;
import androidx.annotation.NonNull;
import com.android.settings.widget.SettingsMainSwitchPreferenceController;
public class BundleGlobalPreferenceController extends
SettingsMainSwitchPreferenceController {
NotificationBackend mBackend;
public BundleGlobalPreferenceController(@NonNull Context context,
@NonNull String preferenceKey) {
super(context, preferenceKey);
mBackend = new NotificationBackend();
}
@Override
public int getAvailabilityStatus() {
if (Flags.notificationClassificationUi() && mBackend.isNotificationBundlingSupported()) {
return AVAILABLE;
}
return CONDITIONALLY_UNAVAILABLE;
}
@Override
public boolean isChecked() {
return mBackend.isNotificationBundlingEnabled(mContext);
}
@Override
public boolean setChecked(boolean isChecked) {
mBackend.setNotificationBundlingEnabled(isChecked);
return true;
}
@Override
public int getSliceHighlightMenuRes() {
// not needed since it's not sliceable
return NO_RES;
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.Flags;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
/**
* Controller for the bundled notifications settings page.
*/
public class BundlePreferenceController extends BasePreferenceController {
NotificationBackend mBackend;
public BundlePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mBackend = new NotificationBackend();
}
@Override
public int getAvailabilityStatus() {
return Flags.notificationClassificationUi() && mBackend.isNotificationBundlingSupported()
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
public CharSequence getSummary() {
return mBackend.isNotificationBundlingEnabled(mContext)
? mContext.getString(R.string.notification_bundle_on)
: mContext.getString(R.string.notification_bundle_off);
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.settings.SettingsEnums;
import android.content.Context;
import android.app.Flags;
import androidx.lifecycle.Lifecycle;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
import org.jetbrains.annotations.NotNull;
/**
* Fragment for bundled notifications.
*/
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class BundlePreferenceFragment extends DashboardFragment {
@Override
public int getMetricsCategory() {
return SettingsEnums.BUNDLED_NOTIFICATIONS;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.bundle_notifications_settings;
}
@Override
protected String getLogTag() {
return "BundlePreferenceFragment";
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.bundle_notifications_settings) {
@Override
protected boolean isPageSearchEnabled(Context context) {
return Flags.notificationClassificationUi();
}
};
}

View File

@@ -0,0 +1,83 @@
/*
* 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.Flags;
import android.content.Context;
import android.service.notification.Adjustment;
import androidx.annotation.NonNull;
import com.android.settings.widget.SettingsMainSwitchPreferenceController;
public class BundleTypePreferenceController extends
SettingsMainSwitchPreferenceController {
static final String PROMO_KEY = "promotions";
static final String NEWS_KEY = "news";
static final String SOCIAL_KEY = "social";
static final String RECS_KEY = "recs";
NotificationBackend mBackend;
int mType;
public BundleTypePreferenceController(@NonNull Context context,
@NonNull String preferenceKey) {
super(context, preferenceKey);
mBackend = new NotificationBackend();
mType = getBundleTypeForKey();
}
@Override
public int getAvailabilityStatus() {
if (Flags.notificationClassificationUi() && mBackend.isNotificationBundlingSupported()
&& mBackend.isNotificationBundlingEnabled(mContext)) {
return AVAILABLE;
}
return CONDITIONALLY_UNAVAILABLE;
}
@Override
public boolean isChecked() {
return mBackend.isBundleTypeApproved(mType);
}
@Override
public boolean setChecked(boolean isChecked) {
mBackend.setBundleTypeState(mType, isChecked);
return true;
}
@Override
public int getSliceHighlightMenuRes() {
// not needed since it's not sliceable
return NO_RES;
}
private @Adjustment.Types int getBundleTypeForKey() {
if (PROMO_KEY.equals(mPreferenceKey)) {
return Adjustment.TYPE_PROMOTION;
} else if (NEWS_KEY.equals(mPreferenceKey)) {
return Adjustment.TYPE_NEWS;
} else if (SOCIAL_KEY.equals(mPreferenceKey)) {
return Adjustment.TYPE_SOCIAL_MEDIA;
} else if (RECS_KEY.equals(mPreferenceKey)) {
return Adjustment.TYPE_CONTENT_RECOMMENDATION;
}
return Adjustment.TYPE_OTHER;
}
}

View File

@@ -20,18 +20,16 @@ import android.content.Context
import android.media.AudioManager
import android.media.AudioManager.STREAM_BLUETOOTH_SCO
import android.media.AudioManager.STREAM_VOICE_CALL
import android.os.UserHandle
import android.os.UserManager.DISALLOW_ADJUST_VOLUME
import android.os.UserManager
import androidx.preference.Preference
import com.android.settings.PreferenceRestrictionMixin
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.metadata.ReadWritePermit
import com.android.settingslib.preference.PreferenceBinding
@@ -44,7 +42,7 @@ open class CallVolumePreference :
RangeValue,
PreferenceAvailabilityProvider,
PreferenceIconProvider,
PreferenceRestrictionProvider {
PreferenceRestrictionMixin {
override val key: String
get() = KEY
@@ -55,18 +53,12 @@ open class CallVolumePreference :
override fun isAvailable(context: Context) =
context.resources.getBoolean(R.bool.config_show_call_volume) &&
!createAudioHelper(context).isSingleVolume()
!createAudioHelper(context).isSingleVolume
override fun isRestricted(context: Context) =
RestrictedLockUtilsInternal.hasBaseUserRestriction(
context,
DISALLOW_ADJUST_VOLUME,
UserHandle.myUserId()
) || RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context,
DISALLOW_ADJUST_VOLUME,
UserHandle.myUserId()
) != null
override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
override val restrictionKey: String
get() = UserManager.DISALLOW_ADJUST_VOLUME
override fun storage(context: Context): KeyValueStore {
val helper = createAudioHelper(context)

View File

@@ -18,18 +18,16 @@ 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.PreferenceRestrictionMixin
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.metadata.ReadWritePermit
import com.android.settingslib.preference.PreferenceBinding
@@ -42,7 +40,7 @@ open class MediaVolumePreference :
RangeValue,
PreferenceAvailabilityProvider,
PreferenceIconProvider,
PreferenceRestrictionProvider {
PreferenceRestrictionMixin {
override val key: String
get() = KEY
@@ -58,17 +56,10 @@ open class MediaVolumePreference :
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 isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
override val restrictionKey: String
get() = UserManager.DISALLOW_ADJUST_VOLUME
override fun storage(context: Context): KeyValueStore {
val helper = createAudioHelper(context)
@@ -107,9 +98,9 @@ open class MediaVolumePreference :
open fun createAudioHelper(context: Context) = AudioHelper(context)
fun updateContentDescription(preference: VolumeSeekBarPreference) {
private fun updateContentDescription(preference: VolumeSeekBarPreference) {
when {
preference.isMuted() ->
preference.isMuted ->
preference.updateContentDescription(
preference.context.getString(
R.string.volume_content_description_silent_mode,

View File

@@ -46,6 +46,7 @@ import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.notification.Adjustment;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.NotificationListenerFilter;
import android.text.format.DateUtils;
@@ -65,9 +66,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class NotificationBackend {
private static final String TAG = "NotificationBackend";
@@ -651,6 +654,59 @@ public class NotificationBackend {
return false;
}
public boolean isNotificationBundlingSupported() {
try {
return !sINM.getUnsupportedAdjustmentTypes().contains(Adjustment.KEY_TYPE);
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
}
return false;
}
public boolean isNotificationBundlingEnabled(Context context) {
try {
return sINM.getAllowedAssistantAdjustments(context.getPackageName())
.contains(Adjustment.KEY_TYPE);
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
}
return false;
}
public void setNotificationBundlingEnabled(boolean enabled) {
try {
if (enabled) {
sINM.allowAssistantAdjustment(Adjustment.KEY_TYPE);
} else {
sINM.disallowAssistantAdjustment(Adjustment.KEY_TYPE);
}
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
}
}
public boolean isBundleTypeApproved(@Adjustment.Types int type) {
try {
int[] approved = sINM.getAllowedAdjustmentKeyTypes();
for (int approvedType : approved) {
if (type == approvedType) {
return true;
}
}
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
}
return false;
}
public void setBundleTypeState(@Adjustment.Types int type, boolean enabled) {
try {
sINM.setAssistantAdjustmentKeyTypeState(type, enabled);
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
}
}
@VisibleForTesting
void setNm(INotificationManager inm) {
sINM = inm;

View File

@@ -24,21 +24,19 @@ 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.UserManager
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.PreferenceRestrictionMixin
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.metadata.ReadWritePermit
import com.android.settingslib.preference.PreferenceBinding
@@ -51,7 +49,8 @@ open class SeparateRingVolumePreference :
RangeValue,
PreferenceAvailabilityProvider,
PreferenceIconProvider,
PreferenceRestrictionProvider {
PreferenceRestrictionMixin {
override val key: String
get() = KEY
@@ -64,21 +63,12 @@ open class SeparateRingVolumePreference :
else -> R.drawable.ic_ring_volume
}
override fun isAvailable(context: Context) = !createAudioHelper(context).isSingleVolume()
override fun isAvailable(context: Context) = !createAudioHelper(context).isSingleVolume
override fun isEnabled(context: Context) =
!RestrictedLockUtilsInternal.hasBaseUserRestriction(
context,
DISALLOW_ADJUST_VOLUME,
UserHandle.myUserId(),
)
override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
override fun isRestricted(context: Context) =
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
context,
DISALLOW_ADJUST_VOLUME,
UserHandle.myUserId(),
) != null
override val restrictionKey: String
get() = UserManager.DISALLOW_ADJUST_VOLUME
override fun storage(context: Context): KeyValueStore {
val helper = createAudioHelper(context)
@@ -118,7 +108,7 @@ open class SeparateRingVolumePreference :
open fun createAudioHelper(context: Context) = AudioHelper(context)
fun updateContentDescription(preference: VolumeSeekBarPreference) {
private fun updateContentDescription(preference: VolumeSeekBarPreference) {
val context = preference.context
val ringerMode = getEffectiveRingerMode(context)
when (ringerMode) {
@@ -152,13 +142,13 @@ open class SeparateRingVolumePreference :
}
}
fun getSuppressionText(context: Context): String? {
private 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()
val hints = notificationManager.hintsFromListenerNoToken
return when {
hintsMatch(hints) -> SuppressorHelper.getSuppressionText(context, suppressor)
else -> null
@@ -167,7 +157,7 @@ open class SeparateRingVolumePreference :
private fun hintsMatch(hints: Int) =
(hints and HINT_HOST_DISABLE_CALL_EFFECTS) != 0 ||
(hints and HINT_HOST_DISABLE_EFFECTS) != 0
(hints and HINT_HOST_DISABLE_EFFECTS) != 0
companion object {
const val KEY = "separate_ring_volume"

View File

@@ -33,11 +33,13 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreferenceHelper;
import com.android.settingslib.RestrictedPreferenceHelperProvider;
/**
* A tri-state preference allowing a user to specify what gets to bubble.
*/
public class BubblePreference extends Preference implements RadioGroup.OnCheckedChangeListener {
public class BubblePreference extends Preference implements RadioGroup.OnCheckedChangeListener,
RestrictedPreferenceHelperProvider {
RestrictedPreferenceHelper mHelper;
private int mSelectedPreference;
@@ -64,6 +66,11 @@ public class BubblePreference extends Preference implements RadioGroup.OnChecked
setLayoutResource(R.layout.bubble_preference);
}
@Override
public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() {
return mHelper;
}
public void setSelectedPreference(int preference) {
mSelectedPreference = preference;
notifyChanged();

View File

@@ -27,6 +27,7 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreferenceHelper;
import com.android.settingslib.RestrictedPreferenceHelperProvider;
import com.android.settingslib.widget.AppPreference;
/**
@@ -34,7 +35,8 @@ import com.android.settingslib.widget.AppPreference;
* {@link com.android.settingslib.RestrictedPreferenceHelper}.
* Used to show policy transparency on {@link AppPreference}.
*/
public class RestrictedAppPreference extends AppPreference {
public class RestrictedAppPreference extends AppPreference implements
RestrictedPreferenceHelperProvider {
private RestrictedPreferenceHelper mHelper;
private String userRestriction;
@@ -58,6 +60,11 @@ public class RestrictedAppPreference extends AppPreference {
this.userRestriction = userRestriction;
}
@Override
public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() {
return mHelper;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);

View File

@@ -23,12 +23,14 @@ import android.util.AttributeSet;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.TwoStatePreference;
import com.android.settings.R;
import com.android.settings.widget.SettingsMainSwitchBar.OnBeforeCheckedChangeListener;
import com.android.settingslib.RestrictedPreferenceHelper;
import com.android.settingslib.RestrictedPreferenceHelperProvider;
import com.android.settingslib.core.instrumentation.SettingsJankMonitor;
import java.util.ArrayList;
@@ -40,7 +42,7 @@ import java.util.List;
* to enable or disable the preferences on the page.
*/
public class SettingsMainSwitchPreference extends TwoStatePreference implements
OnCheckedChangeListener {
OnCheckedChangeListener, RestrictedPreferenceHelperProvider {
private final List<OnBeforeCheckedChangeListener> mBeforeCheckedChangeListeners =
new ArrayList<>();
@@ -71,6 +73,11 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements
init(context, attrs);
}
@Override
public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() {
return mRestrictedHelper;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);

View File

@@ -66,7 +66,6 @@ import com.android.settingslib.development.DevelopmentSettingsEnabler;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -263,7 +262,6 @@ public class MainClearTest {
assertThat(mMainClear.showWipeEuicc()).isTrue();
}
@Ignore("b/313566998")
@Test
public void testShowWipeEuicc_developerMode_unprovisioned() {
prepareEuiccState(

View File

@@ -51,6 +51,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import java.util.List;
import java.util.Objects;
/** Tests for {@link AccessibilityHearingAidsFragment}. */
@RunWith(RobolectricTestRunner.class)
@@ -88,7 +89,9 @@ public class AccessibilityHearingAidsFragmentTest {
mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
final List<String> niks = AccessibilityHearingAidsFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(mContext);
.getNonIndexableKeys(mContext).stream()
.filter(Objects::nonNull)
.toList();
final List<String> keys =
XmlTestUtils.getKeysFromPreferenceXml(mContext, R.xml.accessibility_hearing_aids);

View File

@@ -44,6 +44,7 @@ import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccou
import android.provider.SearchIndexableResource;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
@@ -73,7 +74,7 @@ import java.util.List;
@Config(shadows = ShadowAuthenticationHelper.class)
public class ContactsStorageSettingsTest {
private static final String PREF_KEY_DEVICE_ONLY = "device_only_account_preference";
private static final String PREF_KEY_ACCOUNT_CATEGORY = "account_category";
private static final String PREF_KEY_ADD_ACCOUNT = "add_account";
private static final Account TEST_ACCOUNT1 = new Account("test@gmail.com", "type1");
@@ -95,6 +96,7 @@ public class ContactsStorageSettingsTest {
private PreferenceManager mPreferenceManager;
private TestContactsStorageSettings mContactsStorageSettings;
private PreferenceScreen mScreen;
private PreferenceGroup accountCategory;
@Before
public void setUp() throws Exception {
@@ -103,8 +105,16 @@ public class ContactsStorageSettingsTest {
eq(ContactsContract.AUTHORITY_URI))).thenReturn(mContentProviderClient);
mPreferenceManager = new PreferenceManager(mContext);
when(mContactsStorageSettings.getPreferenceManager()).thenReturn(mPreferenceManager);
mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
mScreen = spy(mPreferenceManager.inflateFromResource(mContext,
R.xml.contacts_storage_settings, mScreen));
when(mScreen.getPreferenceManager()).thenReturn(mPreferenceManager);
accountCategory = mScreen.findPreference(PREF_KEY_ACCOUNT_CATEGORY);
SelectorWithWidgetPreference deviceOnlyPreference = mScreen.findPreference(
PREF_KEY_DEVICE_ONLY);
when(mContactsStorageSettings.findPreference(eq(PREF_KEY_DEVICE_ONLY))).thenReturn(
deviceOnlyPreference);
when(mContactsStorageSettings.findPreference(eq(PREF_KEY_ACCOUNT_CATEGORY))).thenReturn(
accountCategory);
when(mContactsStorageSettings.getPreferenceScreen()).thenReturn(mScreen);
mContactsStorageSettings.onAttach(mContext);
}
@@ -134,17 +144,15 @@ public class ContactsStorageSettingsTest {
when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(),
any())).thenReturn(eligibleAccountBundle);
PreferenceScreen settingScreen = mPreferenceManager.inflateFromResource(mContext,
R.xml.contacts_storage_settings, mScreen);
SelectorWithWidgetPreference deviceOnlyPreference = settingScreen.findPreference(
SelectorWithWidgetPreference deviceOnlyPreference = mContactsStorageSettings.findPreference(
PREF_KEY_DEVICE_ONLY);
when(mContactsStorageSettings.findPreference(eq(PREF_KEY_DEVICE_ONLY))).thenReturn(
deviceOnlyPreference);
assertThat(deviceOnlyPreference.getTitle()).isEqualTo("Device only");
assertThat(deviceOnlyPreference.getSummary()).isEqualTo(
"New contacts won't be synced with an account");
assertThat(deviceOnlyPreference.getOrder()).isEqualTo(999);
assertThat(mContactsStorageSettings.findPreference(
PREF_KEY_ACCOUNT_CATEGORY).getTitle()).isEqualTo("Where to save contacts");
mContactsStorageSettings.refreshUI();
mContactsStorageSettings.onRadioButtonClicked(deviceOnlyPreference);
@@ -175,6 +183,8 @@ public class ContactsStorageSettingsTest {
mContactsStorageSettings.refreshUI();
assertThat(mContactsStorageSettings.findPreference(
PREF_KEY_ACCOUNT_CATEGORY).getTitle()).isEqualTo("Where to save contacts");
assertThat(mScreen.findPreference(PREF_KEY_ADD_ACCOUNT).getTitle()).isEqualTo(
"Add an account to get started");
assertThat(mScreen.findPreference(PREF_KEY_ADD_ACCOUNT).getOrder()).isEqualTo(998);
@@ -232,15 +242,15 @@ public class ContactsStorageSettingsTest {
mContactsStorageSettings.refreshUI();
SelectorWithWidgetPreference account1Preference = mScreen.findPreference(
SelectorWithWidgetPreference account1Preference = accountCategory.findPreference(
String.valueOf(TEST_ACCOUNT1.hashCode()));
assertThat(account1Preference.getTitle()).isEqualTo("LABEL1");
assertThat(account1Preference.getTitle()).isEqualTo("Device and LABEL1");
assertThat(account1Preference.getSummary()).isEqualTo("test@gmail.com");
assertThat(account1Preference.getIcon()).isNotNull();
SelectorWithWidgetPreference account2Preference = mScreen.findPreference(
SelectorWithWidgetPreference account2Preference = accountCategory.findPreference(
String.valueOf(TEST_ACCOUNT2.hashCode()));
assertThat(account2Preference.getTitle()).isEqualTo("LABEL2");
assertThat(account2Preference.getTitle()).isEqualTo("Device and LABEL2");
assertThat(account2Preference.getSummary()).isEqualTo("test@samsung.com");
assertThat(account2Preference.getIcon()).isNotNull();
@@ -286,21 +296,21 @@ public class ContactsStorageSettingsTest {
mContactsStorageSettings.refreshUI();
SelectorWithWidgetPreference account1Preference = mScreen.findPreference(
SelectorWithWidgetPreference account1Preference = accountCategory.findPreference(
String.valueOf(TEST_ACCOUNT1.hashCode()));
assertThat(account1Preference.getTitle()).isEqualTo("LABEL1");
assertThat(account1Preference.getTitle()).isEqualTo("Device and LABEL1");
assertThat(account1Preference.getSummary()).isEqualTo("test@gmail.com");
assertThat(account1Preference.getIcon()).isNotNull();
SelectorWithWidgetPreference account2Preference = mScreen.findPreference(
SelectorWithWidgetPreference account2Preference = accountCategory.findPreference(
String.valueOf(TEST_ACCOUNT2.hashCode()));
assertThat(account2Preference.getTitle()).isEqualTo("LABEL2");
assertThat(account2Preference.getTitle()).isEqualTo("Device and LABEL2");
assertThat(account2Preference.getSummary()).isEqualTo("test@samsung.com");
assertThat(account2Preference.getIcon()).isNotNull();
SelectorWithWidgetPreference account3Preference = mScreen.findPreference(
SelectorWithWidgetPreference account3Preference = accountCategory.findPreference(
String.valueOf(TEST_ACCOUNT3.hashCode()));
assertThat(account3Preference.getTitle()).isEqualTo("LABEL3");
assertThat(account3Preference.getTitle()).isEqualTo("Device and LABEL3");
assertThat(account3Preference.getSummary()).isEqualTo("test@outlook.com");
assertThat(account3Preference.getIcon()).isNotNull();
@@ -327,7 +337,7 @@ public class ContactsStorageSettingsTest {
mContactsStorageSettings.refreshUI();
SelectorWithWidgetPreference simPreference = mScreen.findPreference(
SelectorWithWidgetPreference simPreference = accountCategory.findPreference(
String.valueOf(SIM_ACCOUNT.hashCode()));
assertThat(simPreference.getTitle()).isEqualTo("SIM");
assertThat(simPreference.getSummary()).isEqualTo("SIM");

View File

@@ -25,7 +25,7 @@ import androidx.preference.PreferenceViewHolder
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.PrimarySwitchPreference
import com.android.settingslib.preference.PreferenceDataStoreAdapter
import com.android.settingslib.preference.createAndBindWidget
import com.android.settingslib.widget.SettingsThemeHelper.isExpressiveTheme
import com.android.settingslib.widget.theme.R
import com.google.common.truth.Truth.assertThat
@@ -117,17 +117,14 @@ class AutoBrightnessScreenTest {
assertThat(preferenceScreenCreator.isAvailable(context)).isFalse()
}
private fun getPrimarySwitchPreference(): PrimarySwitchPreference =
preferenceScreenCreator.run {
val preference = createWidget(context)
preference.preferenceDataStore = PreferenceDataStoreAdapter(storage(context))
bind(preference, this)
private fun getPrimarySwitchPreference() =
preferenceScreenCreator.createAndBindWidget<PrimarySwitchPreference>(context).also {
val holder =
PreferenceViewHolder.createInstanceForTests(
LayoutInflater.from(context).inflate(getResId(), /* root= */ null)
)
.apply { findViewById(androidx.preference.R.id.switchWidget) }
preference.apply { onBindViewHolder(holder) }
it.onBindViewHolder(holder)
}
private fun setScreenBrightnessMode(value: Int) =

View File

@@ -0,0 +1,101 @@
/*
* 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 static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_TYPE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Flags;
import android.app.INotificationManager;
import android.content.Context;
import android.platform.test.flag.junit.SetFlagsRule;
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 java.util.List;
@RunWith(RobolectricTestRunner.class)
public class BundleGlobalPreferenceControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PREFERENCE_KEY = "preference_key";
private Context mContext;
BundleGlobalPreferenceController mController;
@Mock
INotificationManager mInm;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mSetFlagsRule.enableFlags(
android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI);
mController = new BundleGlobalPreferenceController(mContext, PREFERENCE_KEY);
mController.mBackend.setNm(mInm);
}
@Test
public void isAvailable_flagEnabledNasSupports_shouldReturnTrue() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void isAvailable_flagEnabledNasDoesNotSupport_shouldReturnFalse() throws Exception {
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of(KEY_TYPE));
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_flagDisabledNasSupports_shouldReturnFalse() {
mSetFlagsRule.disableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isChecked() throws Exception {
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of(KEY_TYPE));
assertThat(mController.isChecked()).isTrue();
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of(KEY_IMPORTANCE));
assertThat(mController.isChecked()).isFalse();
}
@Test
public void setChecked() throws Exception {
mController.setChecked(false);
verify(mInm).disallowAssistantAdjustment(KEY_TYPE);
mController.setChecked(true);
verify(mInm).allowAssistantAdjustment(KEY_TYPE);
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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 static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_TYPE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import android.app.Flags;
import android.app.INotificationManager;
import android.content.Context;
import android.platform.test.flag.junit.SetFlagsRule;
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 java.util.List;
@RunWith(RobolectricTestRunner.class)
public class BundlePreferenceControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PREFERENCE_KEY = "preference_key";
private Context mContext;
BundlePreferenceController mController;
@Mock
INotificationManager mInm;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mSetFlagsRule.enableFlags(
android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI);
mController = new BundlePreferenceController(mContext, PREFERENCE_KEY);
mController.mBackend.setNm(mInm);
}
@Test
public void isAvailable_flagEnabledNasSupports_shouldReturnTrue() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void isAvailable_flagEnabledNasDoesNotSupport_shouldReturnFalse() throws Exception {
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of(KEY_TYPE));
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_flagDisabledNasSupports_shouldReturnFalse() {
mSetFlagsRule.disableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void getSummary() throws Exception {
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of(KEY_TYPE));
assertThat(mController.getSummary()).isEqualTo("On");
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of(KEY_IMPORTANCE));
assertThat(mController.getSummary()).isEqualTo("Off");
}
}

View File

@@ -0,0 +1,171 @@
/*
* 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 static android.service.notification.Adjustment.KEY_TYPE;
import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
import static android.service.notification.Adjustment.TYPE_NEWS;
import static android.service.notification.Adjustment.TYPE_PROMOTION;
import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Flags;
import android.app.INotificationManager;
import android.content.Context;
import android.os.RemoteException;
import android.platform.test.flag.junit.SetFlagsRule;
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 java.util.List;
@RunWith(RobolectricTestRunner.class)
public class BundleTypePreferenceControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PREFERENCE_KEY = "preference_key";
private Context mContext;
BundleTypePreferenceController mController;
@Mock
INotificationManager mInm;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of(KEY_TYPE));
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of());
mSetFlagsRule.enableFlags(
android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION,
Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI);
mContext = RuntimeEnvironment.application;
mController = new BundleTypePreferenceController(mContext, PREFERENCE_KEY);
mController.mBackend.setNm(mInm);
}
@Test
public void isAvailable() throws RemoteException {
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of(KEY_TYPE));
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void isAvailable_flagEnabledNasDoesNotSupport_shouldReturnFalse()
throws RemoteException {
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of(KEY_TYPE));
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of(KEY_TYPE));
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_flagDisabledNasSupports_shouldReturnFalse() throws RemoteException {
mSetFlagsRule.disableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI);
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of());
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of(KEY_TYPE));
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_flagEnabledNasDisabled_shouldReturnFalse() throws RemoteException {
when(mInm.getUnsupportedAdjustmentTypes()).thenReturn(List.of());
when(mInm.getAllowedAssistantAdjustments(any())).thenReturn(List.of());
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isChecked_promotions() throws RemoteException {
mController = new BundleTypePreferenceController(mContext,
BundleTypePreferenceController.PROMO_KEY);
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(new int[]{TYPE_PROMOTION});
assertThat(mController.isChecked()).isTrue();
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(new int[]{});
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_news() throws RemoteException {
mController = new BundleTypePreferenceController(mContext,
BundleTypePreferenceController.NEWS_KEY);
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(new int[]{TYPE_NEWS});
assertThat(mController.isChecked()).isTrue();
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(new int[]{});
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_social() throws RemoteException {
mController = new BundleTypePreferenceController(mContext,
BundleTypePreferenceController.SOCIAL_KEY);
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(new int[]{TYPE_SOCIAL_MEDIA});
assertThat(mController.isChecked()).isTrue();
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(new int[]{});
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_recs() throws RemoteException {
mController = new BundleTypePreferenceController(mContext,
BundleTypePreferenceController.RECS_KEY);
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(
new int[]{TYPE_CONTENT_RECOMMENDATION});
assertThat(mController.isChecked()).isTrue();
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(new int[]{});
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_mixed() throws RemoteException {
mController = new BundleTypePreferenceController(mContext,
BundleTypePreferenceController.RECS_KEY);
when(mInm.getAllowedAdjustmentKeyTypes()).thenReturn(
new int[]{TYPE_PROMOTION, TYPE_CONTENT_RECOMMENDATION});
assertThat(mController.isChecked()).isTrue();
}
@Test
public void setChecked() throws RemoteException {
mController = new BundleTypePreferenceController(mContext,
BundleTypePreferenceController.PROMO_KEY);
mController.setChecked(false);
verify(mInm).setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, false);
mController.setChecked(true);
verify(mInm).setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, true);
}
}

View File

@@ -29,6 +29,7 @@ import com.android.settings.biometrics.fingerprint2.domain.interactor.Accessibil
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.lib.model.Orientation
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSIconTouchViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
@@ -78,6 +79,7 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
override val isEnabled: Boolean
get() = true
override fun announce(clazz: Class<*>, announcement: CharSequence?) {}
override fun interrupt() {}
}
var foldStateInteractor =
@@ -97,6 +99,7 @@ class Injector(step: FingerprintNavigationStep.UiStep) {
override val rotationFromDefault: Flow<Int> = rotation
override fun getRotationFromDefault(rotation: Int): Int = rotation
override val orientationChanged: Flow<Orientation> = flowOf(Orientation.Portrait)
}
var gatekeeperViewModel = FingerprintGatekeeperViewModel(fingerprintManagerInteractor)

View File

@@ -30,6 +30,7 @@ import com.android.settings.biometrics.fingerprint2.domain.interactor.Accessibil
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.lib.model.Orientation
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
@@ -111,6 +112,8 @@ class FingerprintEnrollFindSensorViewModelV2Test {
override val isEnabled: Boolean
get() = true
override fun announce(clazz: Class<*>, announcement: CharSequence?) {}
override fun interrupt() {
}
}
foldStateInteractor =
object : FoldStateInteractor {
@@ -128,6 +131,7 @@ class FingerprintEnrollFindSensorViewModelV2Test {
override val rotationFromDefault: Flow<Int> = flowOf(Surface.ROTATION_0)
override fun getRotationFromDefault(rotation: Int): Int = rotation
override val orientationChanged: Flow<Orientation> = flowOf(Orientation.Portrait)
}
underTest =
FingerprintEnrollFindSensorViewModel(