Snap for 9754537 from 5b5da43ef8 to udc-release

Change-Id: I6e42b7caf0be232206900c179f44174d663c9d7b
This commit is contained in:
Android Build Coastguard Worker
2023-03-16 03:26:55 +00:00
42 changed files with 847 additions and 1139 deletions

View File

@@ -20,6 +20,7 @@
android:id="@+id/panel_container"
android:layout_width="@dimen/settings_panel_width"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:layout_gravity="center_horizontal"
android:background="@drawable/settings_panel_rounded_top_corner_background" >

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout android:id="@+id/zen_mode_settings_senders_overlay_view"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/zen_conversations_image_margin_vertical"
android:layout_marginBottom="@dimen/zen_conversations_image_margin_vertical">
</RelativeLayout>
</RelativeLayout>

View File

@@ -51,9 +51,6 @@
<dimen name="conversation_icon_size">32dp</dimen>
<dimen name="zen_mode_settings_button_margin_vertical">24dp</dimen>
<dimen name="zen_conversations_image_margin_vertical">24dp</dimen>
<dimen name="zen_conversations_icon_offset">32dp</dimen>
<dimen name="zen_conversations_icon_size">50dp</dimen>
<dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
<dimen name="zen_schedule_day_margin">17dp</dimen>

View File

@@ -8177,8 +8177,6 @@
<!-- [CHAR LIMIT=120] Zen mode settings: Title for conversations settings page -->
<string name="zen_mode_conversations_title">Conversations</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Header for conversations settings page -->
<string name="zen_mode_conversations_section_title">Conversations that can interrupt</string>
<string name="zen_mode_from_all_conversations">All conversations</string>
<string name="zen_mode_from_important_conversations">Priority conversations</string>
<!-- [CHAR LIMIT=40] Version of the above for "priority conversations" when it is a non-first member of a list -->
@@ -11698,6 +11696,10 @@
<string name="dream_complications_toggle_title">Show additional information</string>
<!-- The summary of what overlays this toggle controls [CHAR LIMIT=none] -->
<string name="dream_complications_toggle_summary">Display things like the time, weather, or other information on the screen saver</string>
<!-- The title of the toggle which enables/disables the home controls button on top of the screen saver [CHAR LIMIT=none] -->
<string name="dream_home_controls_toggle_title">Show home controls</string>
<!-- The summary of the home controls toggle [CHAR LIMIT=none] -->
<string name="dream_home_controls_toggle_summary">Show home controls button from the screen saver</string>
<!-- The title of the category to show for the screensaver miscellaneous settings [CHAR LIMIT=none] -->
<string name="dream_more_settings_category">More settings</string>
<!-- The title of the screen saver setup page [CHAR LIMIT=none] -->

View File

@@ -220,6 +220,7 @@
<!-- Note that Dialog themes do not set list dividers -->
<style name="Theme.Panel" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog">
<item name="android:windowBackground">@null</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:dividerHorizontal">@*android:drawable/list_divider_material</item>
<item name="android:windowNoTitle">true</item>
<item name="android:listDivider">@*android:drawable/list_divider_material</item>

View File

@@ -26,17 +26,15 @@
<com.android.settings.widget.SettingsMainSwitchPreference
android:key="block" />
<com.android.settingslib.widget.FooterPreference
<Preference
android:key="block_desc" />
<!-- Conversations added here -->
<PreferenceCategory
android:title="@string/conversations_category_title"
android:key="conversations"
android:visibility="gone"
settings:allowDividerAbove="false"
settings:allowDividerBelow="false">
android:visibility="gone">
</PreferenceCategory>
<com.android.settingslib.RestrictedSwitchPreference
android:key="invalid_conversation_switch"
@@ -49,25 +47,13 @@
android:key="bubble_pref_link"
android:title="@string/notification_bubbles_title"
android:icon="@drawable/ic_create_bubble"
settings:allowDividerAbove="false"
settings:controller="com.android.settings.notification.app.BubbleSummaryPreferenceController">
</Preference>
<!-- Channels/Channel groups added here -->
<PreferenceCategory
android:key="channels"
android:layout="@layout/empty_view"
settings:allowDividerAbove="true"
settings:allowDividerBelow="true" />
<!-- Show badge -->
<com.android.settingslib.RestrictedSwitchPreference
android:key="badge"
android:title="@string/notification_badge_title"
settings:useAdditionalSummary="true"
android:order="1001"
settings:allowDividerAbove="true"
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
android:layout="@layout/empty_view" />
<!-- Importance toggle -->
<com.android.settingslib.RestrictedSwitchPreference
@@ -86,18 +72,25 @@
android:title="@string/app_notification_override_dnd_title"
android:summary="@string/app_notification_override_dnd_summary"/>
<Preference
android:key="app_link"
android:order="1003"
android:icon="@drawable/ic_settings_24dp"
android:title="@string/app_settings_link" />
<!-- Show badge -->
<com.android.settingslib.RestrictedSwitchPreference
android:key="badge"
android:title="@string/notification_badge_title"
settings:useAdditionalSummary="true"
android:order="1001"
android:icon="@drawable/ic_notification_dot"
settings:allowDividerAbove="true"
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
<com.android.settingslib.widget.FooterPreference
android:key="desc"
android:order="5000" />
<Preference
android:key="app_link"
android:order="1003"
android:icon="@drawable/ic_settings_24dp"
android:title="@string/app_settings_link" />
<com.android.settingslib.widget.FooterPreference
android:key="deleted"
android:icon="@drawable/ic_trash_can"
android:order="8000" />
</PreferenceScreen>

View File

@@ -46,6 +46,12 @@
android:summary="@string/dream_complications_toggle_summary"
settings:controller="com.android.settings.dream.DreamComplicationPreferenceController"/>
<SwitchPreference
android:key="dream_home_controls_toggle"
android:title="@string/dream_home_controls_toggle_title"
android:summary="@string/dream_home_controls_toggle_summary"
settings:controller="com.android.settings.dream.DreamHomeControlsPreferenceController"/>
<com.android.settings.applications.SpacePreference
android:layout_height="16dp" />

View File

@@ -37,5 +37,13 @@
android:name="classname"
android:value="com.android.settings.applications.appinfo.AppLocaleDetails" />
</Preference>
<Preference
android:key="regional_preferences"
android:title="@string/regional_preferences_title"
android:summary="@string/regional_preferences_summary"
android:fragment="com.android.settings.regionalpreferences.RegionalPreferencesEntriesFragment"
settings:controller="com.android.settings.regionalpreferences.RegionalPreferencesController" />
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 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"
android:key="zen_mode_conversations_settings"
android:title="@string/zen_mode_conversations_title">
<!-- Conversations -->
<PreferenceCategory
android:key="zen_mode_conversations_radio_buttons"
android:title="@string/zen_mode_conversations_section_title">
<!-- Senders image -->
<com.android.settingslib.widget.LayoutPreference
android:key="zen_mode_conversations_image"
android:layout="@layout/zen_mode_senders_overlay_image"
android:selectable="false"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -18,6 +18,7 @@ package com.android.settings.accessibility;
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
@@ -72,8 +73,7 @@ public class AccessibilityHearingAidsFragment extends AccessibilityShortcutPrefe
@Override
public int getMetricsCategory() {
// TODO(b/262839191): To be updated settings_enums.proto
return 0;
return SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS;
}
@Override

View File

@@ -16,6 +16,7 @@
package com.android.settings.accessibility;
import android.app.settings.SettingsEnums;
import android.content.Context;
import com.android.settings.R;
@@ -41,8 +42,7 @@ public class FlashNotificationsPreferenceFragment extends DashboardFragment {
@Override
public int getMetricsCategory() {
// TODO: Flash notifications have to add SettingsEnums.
return 0;
return SettingsEnums.FLASH_NOTIFICATION_SETTINGS;
}
@Override

View File

@@ -16,6 +16,7 @@
package com.android.settings.accessibility;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.le.ScanFilter;
@@ -61,8 +62,7 @@ public class HearingDevicePairingDetail extends BluetoothDevicePairingDetailBase
@Override
public int getMetricsCategory() {
// TODO(b/262839191): To be updated settings_enums.proto
return 0;
return SettingsEnums.HEARING_AID_PAIRING;
}
@Override

View File

@@ -24,7 +24,9 @@ import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.credentials.SetEnabledProvidersException;
@@ -32,6 +34,7 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.OutcomeReceiver;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
@@ -162,10 +165,54 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
PreferenceGroup group = screen.findPreference(getPreferenceKey());
Context context = screen.getContext();
mPrefs.putAll(buildPreferenceList(context, group));
}
for (CredentialProviderInfo service : mServices) {
group.addPreference(createPreference(context, service));
/** Aggregates the list of services and builds a list of UI prefs to show. */
@VisibleForTesting
public Map<String, SwitchPreference> buildPreferenceList(
Context context, PreferenceGroup group) {
// Group the services by package name.
Map<String, List<CredentialProviderInfo>> groupedInfos = new HashMap<>();
for (CredentialProviderInfo cpi : mServices) {
String packageName = cpi.getServiceInfo().packageName;
if (!groupedInfos.containsKey(packageName)) {
groupedInfos.put(packageName, new ArrayList<>());
}
groupedInfos.get(packageName).add(cpi);
}
// Build the pref list.
Map<String, SwitchPreference> output = new HashMap<>();
for (String packageName : groupedInfos.keySet()) {
List<CredentialProviderInfo> infos = groupedInfos.get(packageName);
CredentialProviderInfo firstInfo = infos.get(0);
ServiceInfo firstServiceInfo = firstInfo.getServiceInfo();
CharSequence title = firstInfo.getLabel(context);
Drawable icon = firstInfo.getServiceIcon(context);
if (infos.size() > 1) {
// If there is more than one then group them under the package.
ApplicationInfo appInfo = firstServiceInfo.applicationInfo;
if (appInfo.nonLocalizedLabel != null) {
title = appInfo.loadLabel(mPm);
}
icon = mIconFactory.getBadgedIcon(appInfo, getUser());
}
// If there is no title then don't show anything.
if (TextUtils.isEmpty(title)) {
continue;
}
// Build the pref and add it to the output & group.
SwitchPreference pref = addProviderPreference(context, title, icon, packageName);
output.put(packageName, pref);
group.addPreference(pref);
}
return output;
}
/** Creates a preference object based on the provider info. */
@@ -238,7 +285,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
final SwitchPreference pref = new SwitchPreference(prefContext);
pref.setTitle(title);
pref.setChecked(mEnabledPackageNames.contains(packageName));
mPrefs.put(packageName, pref);
if (icon != null) {
pref.setIcon(Utils.getSafeIcon(icon));

View File

@@ -20,6 +20,7 @@ import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.util.Log;
@@ -32,10 +33,8 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.search.SearchIndexable;
/** Settings fragment containing bluetooth audio routing. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class BluetoothDetailsAudioRoutingFragment extends RestrictedDashboardFragment {
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
@@ -73,8 +72,7 @@ public class BluetoothDetailsAudioRoutingFragment extends RestrictedDashboardFra
@Override
public int getMetricsCategory() {
// TODO(b/262839191): To be updated settings_enums.proto
return 0;
return SettingsEnums.BLUETOOTH_AUDIO_ROUTING;
}
@Override

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dream;
import android.content.Context;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settingslib.dream.DreamBackend;
/**
* Controller for the {@link androidx.preference.SwitchPreference} which controls if dream
* overlays should be enabled.
*/
public class DreamHomeControlsPreferenceController extends TogglePreferenceController {
private final DreamBackend mBackend;
public DreamHomeControlsPreferenceController(Context context, String key) {
this(context, key, DreamBackend.getInstance(context));
}
@VisibleForTesting
public DreamHomeControlsPreferenceController(Context context, String key,
DreamBackend dreamBackend) {
super(context, key);
mBackend = dreamBackend;
}
@Override
public int getAvailabilityStatus() {
final boolean supported =
mBackend.getSupportedComplications()
.contains(DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS);
return supported ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
public boolean isChecked() {
return mBackend.getEnabledComplications().contains(
DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS);
}
@Override
public boolean setChecked(boolean isChecked) {
mBackend.setHomeControlsEnabled(isChecked);
return true;
}
@Override
public int getSliceHighlightMenuRes() {
return R.string.menu_key_display;
}
}

View File

@@ -37,10 +37,10 @@ import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.inputmethod.NewKeyboardSettingsUtils.KeyboardInfo;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
implements InputManager.InputDeviceListener {
@@ -53,7 +53,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
private int mUserId;
private int mInputDeviceId;
private Context mContext;
private Map<String, KeyboardInfo> mKeyboardLanguageLayouts = new HashMap<>();
private ArrayList<KeyboardInfo> mKeyboardInfoList = new ArrayList<>();
@Override
public void onActivityCreated(final Bundle icicle) {
@@ -74,8 +74,16 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.removeAll();
List<InputMethodInfo> infoList = mImm.getEnabledInputMethodListAsUser(mUserId);
Collections.sort(infoList, new Comparator<InputMethodInfo>() {
public int compare(InputMethodInfo o1, InputMethodInfo o2) {
String s1 = o1.loadLabel(mContext.getPackageManager()).toString();
String s2 = o2.loadLabel(mContext.getPackageManager()).toString();
return s1.compareTo(s2);
}
});
for (InputMethodInfo info : infoList) {
mKeyboardLanguageLayouts.clear();
mKeyboardInfoList.clear();
List<InputMethodSubtype> subtypes =
mImm.getEnabledInputMethodSubtypeList(info, true);
for (InputMethodSubtype subtype : subtypes) {
@@ -88,51 +96,58 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
}
private void mapLanguageWithLayout(InputMethodInfo info, InputMethodSubtype subtype) {
CharSequence subtypeLabel = getSubtypeLabel(mContext, info, subtype);
KeyboardLayout[] keyboardLayouts = getKeyboardLayouts(info, subtype);
String layout = getKeyboardLayout(info, subtype);
String language = getLanguage(info, subtype);
if (layout != null) {
for (int i = 0; i < keyboardLayouts.length; i++) {
if (keyboardLayouts[i].getDescriptor().equals(layout)) {
KeyboardInfo keyboardInfo = new KeyboardInfo(
language,
subtypeLabel,
keyboardLayouts[i].getLabel(),
info,
subtype);
mKeyboardLanguageLayouts.put(subtype.getLanguageTag(), keyboardInfo);
mKeyboardInfoList.add(keyboardInfo);
break;
}
}
} else {
// if there is no auto-selected layout, we should show "Default"
KeyboardInfo keyboardInfo = new KeyboardInfo(
language,
subtypeLabel,
mContext.getString(R.string.keyboard_default_layout),
info,
subtype);
mKeyboardLanguageLayouts.put(subtype.getLanguageTag(), keyboardInfo);
mKeyboardInfoList.add(keyboardInfo);
}
}
private void updatePreferenceLayout(PreferenceScreen preferenceScreen, InputMethodInfo info) {
if (mKeyboardLanguageLayouts.isEmpty()) {
if (mKeyboardInfoList.isEmpty()) {
return;
}
PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
preferenceCategory.setTitle(info.loadLabel(mContext.getPackageManager()).toString());
preferenceCategory.setTitle(info.loadLabel(mContext.getPackageManager()));
preferenceCategory.setKey(info.getPackageName());
preferenceScreen.addPreference(preferenceCategory);
for (Map.Entry<String, KeyboardInfo> entry : mKeyboardLanguageLayouts.entrySet()) {
Collections.sort(mKeyboardInfoList, new Comparator<KeyboardInfo>() {
public int compare(KeyboardInfo o1, KeyboardInfo o2) {
String s1 = o1.getSubtypeLabel().toString();
String s2 = o2.getSubtypeLabel().toString();
return s1.compareTo(s2);
}
});
for (KeyboardInfo keyboardInfo : mKeyboardInfoList) {
final Preference pref = new Preference(mContext);
String key = "keyboard_language_" + entry.getKey();
NewKeyboardSettingsUtils.KeyboardInfo keyboardInfo = entry.getValue();
pref.setKey(key);
pref.setTitle(keyboardInfo.getLanguage());
pref.setKey(keyboardInfo.getPrefId());
pref.setTitle(keyboardInfo.getSubtypeLabel());
pref.setSummary(keyboardInfo.getLayout());
pref.setOnPreferenceClickListener(
preference -> {
showKeyboardLayoutPicker(
keyboardInfo.getLanguage(),
keyboardInfo.getSubtypeLabel(),
keyboardInfo.getLayout(),
mInputDeviceIdentifier,
mUserId,
@@ -215,7 +230,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
}
private void showKeyboardLayoutPicker(
String language,
CharSequence subtypeLabel,
String layout,
InputDeviceIdentifier inputDeviceIdentifier,
int userId,
@@ -229,7 +244,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
arguments.putParcelable(
NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE, inputMethodSubtype);
arguments.putInt(NewKeyboardSettingsUtils.EXTRA_USER_ID, userId);
arguments.putString(NewKeyboardSettingsUtils.EXTRA_TITLE, language);
arguments.putCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE, subtypeLabel);
arguments.putString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT, layout);
new SubSettingLauncher(mContext)
.setSourceMetricsCategory(getMetricsCategory())
@@ -248,16 +263,9 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
mInputDeviceIdentifier, mUserId, info, subtype);
}
private String getLanguage(InputMethodInfo info, InputMethodSubtype subtype) {
String language;
if (subtype.getLanguageTag().isEmpty()) {
language = subtype.getDisplayName(
mContext,
info.getPackageName(),
info.getServiceInfo().applicationInfo).toString();
} else {
language = Locale.forLanguageTag(subtype.getLanguageTag()).getDisplayName();
}
return language;
private CharSequence getSubtypeLabel(
Context context, InputMethodInfo info, InputMethodSubtype subtype) {
return subtype.getDisplayName(
context, info.getPackageName(), info.getServiceInfo().applicationInfo);
}
}

View File

@@ -36,7 +36,7 @@ public class NewKeyboardLayoutPickerContent extends DashboardFragment {
super.onAttach(context);
InputManager inputManager = getContext().getSystemService(InputManager.class);
Bundle arguments = getArguments();
final String title = arguments.getString(NewKeyboardSettingsUtils.EXTRA_TITLE);
final CharSequence title = arguments.getCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE);
final String layout = arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT);
final int userId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID);
final InputDeviceIdentifier identifier =

View File

@@ -72,24 +72,28 @@ public class NewKeyboardSettingsUtils {
}
static class KeyboardInfo {
String mLanguage;
CharSequence mSubtypeLabel;
String mLayout;
InputMethodInfo mInputMethodInfo;
InputMethodSubtype mInputMethodSubtype;
KeyboardInfo(
String language,
CharSequence subtypeLabel,
String layout,
InputMethodInfo inputMethodInfo,
InputMethodSubtype inputMethodSubtype) {
mLanguage = language;
mSubtypeLabel = subtypeLabel;
mLayout = layout;
mInputMethodInfo = inputMethodInfo;
mInputMethodSubtype = inputMethodSubtype;
}
String getLanguage() {
return mLanguage;
String getPrefId() {
return mInputMethodInfo.getId() + "_" + mInputMethodSubtype.hashCode();
}
CharSequence getSubtypeLabel() {
return mSubtypeLabel;
}
String getLayout() {

View File

@@ -16,12 +16,22 @@
package com.android.settings.language;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.FeatureFlagUtils;
import com.android.settings.Settings;
import com.android.settings.core.BasePreferenceController;
/**
* This is a display controller for new language activity entry.
* TODO(b/273642892): When new layout is on board, this class shall be removed.
*/
public class LanguagePreferenceController extends BasePreferenceController {
private static final String TAG = LanguagePreferenceController.class.getSimpleName();
private boolean mCacheIsFeatureOn = false;
public LanguagePreferenceController(Context context, String key) {
super(context, key);
@@ -31,6 +41,27 @@ public class LanguagePreferenceController extends BasePreferenceController {
public int getAvailabilityStatus() {
boolean isFeatureOn = FeatureFlagUtils
.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
// LanguageSettingsActivity is a new entry page for new language layout.
// LanguageAndInputSettingsActivity is existed entry page for current language layout.
if (mCacheIsFeatureOn != isFeatureOn) {
setActivityEnabled(
mContext, Settings.LanguageAndInputSettingsActivity.class, !isFeatureOn);
setActivityEnabled(mContext, Settings.LanguageSettingsActivity.class, isFeatureOn);
mCacheIsFeatureOn = isFeatureOn;
}
return isFeatureOn ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
private static void setActivityEnabled(Context context, Class klass, final boolean isEnabled) {
PackageManager packageManager = context.getPackageManager();
ComponentName componentName =
new ComponentName(context, klass);
final int flag = isEnabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
packageManager.setComponentEnabledSetting(
componentName, flag, PackageManager.DONT_KILL_APP);
}
}

View File

@@ -272,7 +272,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme
use(OpenNetworkSelectPagePreferenceController.class).init(mSubId);
final AutoSelectPreferenceController autoSelectPreferenceController =
use(AutoSelectPreferenceController.class)
.init(mSubId)
.init(getLifecycle(), mSubId)
.addListener(openNetworkSelectPagePreferenceController);
use(NetworkPreferenceCategoryController.class).init(mSubId)
.setChildren(Arrays.asList(autoSelectPreferenceController));

View File

@@ -34,8 +34,10 @@ import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
@@ -45,6 +47,7 @@ import androidx.preference.SwitchPreference;
import com.android.settings.R;
import com.android.settings.network.AllowedNetworkTypesListener;
import com.android.settings.network.CarrierConfigCache;
import com.android.settings.network.helper.ServiceStateStatus;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.network.telephony.TelephonyTogglePreferenceController;
import com.android.settingslib.utils.ThreadUtils;
@@ -62,6 +65,9 @@ import java.util.concurrent.atomic.AtomicLong;
public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController
implements LifecycleObserver{
private static final long MINIMUM_DIALOG_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1);
private static final String LOG_TAG = "AutoSelectPreferenceController";
private static final String INTERNAL_LOG_TAG_INIT = "Init";
private static final String INTERNAL_LOG_TAG_AFTERSET = "AfterSet";
private final Handler mUiHandler;
private PreferenceScreen mPreferenceScreen;
@@ -76,6 +82,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
private AtomicBoolean mUpdatingConfig;
private int mCacheOfModeStatus;
private AtomicLong mRecursiveUpdate;
ServiceStateStatus mServiceStateStatus;
public AutoSelectPreferenceController(Context context, String key) {
super(context, key);
@@ -129,12 +136,6 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
@Override
public boolean isChecked() {
if (!mUpdatingConfig.get()) {
mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode();
for (OnNetworkSelectModeListener lsn : mListeners) {
lsn.onNetworkSelectModeUpdated(mCacheOfModeStatus);
}
}
return mCacheOfModeStatus == TelephonyManager.NETWORK_SELECTION_MODE_AUTO;
}
@@ -197,12 +198,22 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
//Update UI in UI thread
final long durationMillis = SystemClock.elapsedRealtime() - startMillis;
mUiHandler.postDelayed(() -> {
mRecursiveUpdate.getAndIncrement();
mSwitchPreference.setEnabled(true);
mSwitchPreference.setChecked(isChecked());
mRecursiveUpdate.decrementAndGet();
dismissProgressBar();
ThreadUtils.postOnBackgroundThread(() -> {
queryNetworkSelectionMode(INTERNAL_LOG_TAG_AFTERSET);
//Update UI in UI thread
mUiHandler.post(() -> {
mRecursiveUpdate.getAndIncrement();
if (mSwitchPreference != null) {
mSwitchPreference.setEnabled(true);
mSwitchPreference.setChecked(isChecked());
}
mRecursiveUpdate.decrementAndGet();
dismissProgressBar();
});
});
}, Math.max(MINIMUM_DIALOG_TIME_MILLIS - durationMillis, 0));
});
}
@@ -210,7 +221,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
/**
* Initialization based on given subscription id.
**/
public AutoSelectPreferenceController init(int subId) {
public AutoSelectPreferenceController init(Lifecycle lifecycle, int subId) {
mSubId = subId;
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mSubId);
@@ -221,6 +232,29 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL)
: false;
mServiceStateStatus = new ServiceStateStatus(lifecycle, mTelephonyManager,
new HandlerExecutor(mUiHandler)) {
@Override
protected void setValue(ServiceState status) {
if (status == null) {
return;
}
updateUiAutoSelectValue(status);
}
};
ThreadUtils.postOnBackgroundThread(() -> {
queryNetworkSelectionMode(INTERNAL_LOG_TAG_INIT);
//Update UI in UI thread
mUiHandler.post(() -> {
if (mSwitchPreference != null) {
mRecursiveUpdate.getAndIncrement();
mSwitchPreference.setChecked(isChecked());
mRecursiveUpdate.decrementAndGet();
}
});
});
return this;
}
@@ -230,6 +264,41 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
return this;
}
private void queryNetworkSelectionMode(String tag) {
mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode();
Log.d(LOG_TAG, tag + ": query commend done. mCacheOfModeStatus: " + mCacheOfModeStatus);
updateListenerValue();
}
@VisibleForTesting
void updateUiAutoSelectValue(ServiceState status) {
if (status == null) {
return;
}
if (!mUpdatingConfig.get()) {
int networkSelectionMode = status.getIsManualSelection()
? TelephonyManager.NETWORK_SELECTION_MODE_MANUAL
: TelephonyManager.NETWORK_SELECTION_MODE_AUTO;
if (mCacheOfModeStatus == networkSelectionMode) {
return;
}
mCacheOfModeStatus = networkSelectionMode;
Log.d(LOG_TAG, "updateUiAutoSelectValue: mCacheOfModeStatus: " + mCacheOfModeStatus);
updateListenerValue();
mRecursiveUpdate.getAndIncrement();
updateState(mSwitchPreference);
mRecursiveUpdate.decrementAndGet();
}
}
private void updateListenerValue() {
for (OnNetworkSelectModeListener lsn : mListeners) {
lsn.onNetworkSelectModeUpdated(mCacheOfModeStatus);
}
}
private void showAutoSelectProgressBar() {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(mContext);

View File

@@ -19,6 +19,8 @@ package com.android.settings.notification;
import static com.android.settings.notification.SettingPref.TYPE_GLOBAL;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.provider.Settings.Global;
@@ -41,7 +43,7 @@ public class DockAudioMediaPreferenceController extends SettingPrefController {
DEFAULT_DOCK_AUDIO_MEDIA, DOCK_AUDIO_MEDIA_DISABLED, DOCK_AUDIO_MEDIA_ENABLED) {
@Override
public boolean isApplicable(Context context) {
return context.getResources().getBoolean(
return isLeDesk() && context.getResources().getBoolean(
com.android.settings.R.bool.has_dock_settings);
}
@@ -60,4 +62,18 @@ public class DockAudioMediaPreferenceController extends SettingPrefController {
}
};
}
/**
* Checks the state of docking type
* @return true if it is low-end dock types
*/
private boolean isLeDesk() {
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
Intent dockStatus = mContext.registerReceiver(null, intentFilter);
if (dockStatus == null) {
return false;
}
int dockState = dockStatus.getIntExtra(Intent.EXTRA_DOCK_STATE, -1);
return dockState == Intent.EXTRA_DOCK_STATE_LE_DESK;
}
}

View File

@@ -98,14 +98,13 @@ public class AppNotificationSettings extends NotificationSettings {
mBackend));
mControllers.add(new DndPreferenceController(context, mBackend));
mControllers.add(new AppLinkPreferenceController(context));
mControllers.add(new DescriptionPreferenceController(context));
mControllers.add(new NotificationsOffPreferenceController(context));
mControllers.add(new DeletedChannelsPreferenceController(context, mBackend));
mControllers.add(new ChannelListPreferenceController(context, mBackend));
mControllers.add(new AppConversationListPreferenceController(context, mBackend));
mControllers.add(new InvalidConversationInfoPreferenceController(context, mBackend));
mControllers.add(new InvalidConversationPreferenceController(context, mBackend));
mControllers.add(new BubbleSummaryPreferenceController(context, mBackend));
mControllers.add(new NotificationsOffPreferenceController(context));
mControllers.add(new DeletedChannelsPreferenceController(context, mBackend));
return new ArrayList<>(mControllers);
}
}

View File

@@ -62,9 +62,16 @@ public class BadgePreferenceController extends NotificationPreferenceController
if (isDefaultChannel()) {
return true;
} else {
return mAppRow == null ? false : mAppRow.showBadge;
return mAppRow == null
? false
: mAppRow.channelCount == 0
? false
: mAppRow.showBadge;
}
}
if (mAppRow.channelCount == 0) {
return false;
}
return true;
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright (C) 2017 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.app;
import android.content.Context;
import android.text.TextUtils;
import androidx.preference.Preference;
import com.android.settings.core.PreferenceControllerMixin;
public class DescriptionPreferenceController extends NotificationPreferenceController
implements PreferenceControllerMixin {
private static final String KEY_DESC = "desc";
public DescriptionPreferenceController(Context context) {
super(context, null);
}
@Override
public String getPreferenceKey() {
return KEY_DESC;
}
@Override
public boolean isAvailable() {
if (!super.isAvailable()) {
return false;
}
if (mChannel == null && !hasValidGroup()) {
return false;
}
if (mChannel != null && !TextUtils.isEmpty(mChannel.getDescription())) {
return true;
}
if (hasValidGroup() && !TextUtils.isEmpty(mChannelGroup.getDescription())) {
return true;
}
return false;
}
@Override
boolean isIncludedInFilter() {
return false;
}
public void updateState(Preference preference) {
if (mAppRow != null) {
if (mChannel != null) {
preference.setTitle(mChannel.getDescription());
} else if (hasValidGroup()) {
preference.setTitle(mChannelGroup.getDescription());
}
}
preference.setEnabled(false);
preference.setSelectable(false);
}
}

View File

@@ -312,21 +312,6 @@ public class ZenModeBackend {
return R.string.zen_mode_from_no_conversations;
}
protected int getConversationSummary() {
int conversationType = getPriorityConversationSenders();
switch (conversationType) {
case NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE:
return R.string.zen_mode_from_all_conversations;
case NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT:
return R.string.zen_mode_from_important_conversations;
case NotificationManager.Policy.CONVERSATION_SENDERS_NONE:
return R.string.zen_mode_from_no_conversations;
default:
return R.string.zen_mode_from_no_conversations;
}
}
protected int getContactsCallsSummary(ZenPolicy policy) {
int peopleType = policy.getPriorityCallSenders();
switch (peopleType) {

View File

@@ -1,167 +0,0 @@
/*
* Copyright (C) 2020 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.zen;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_NONE;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.service.notification.ConversationChannelWrapper;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.LayoutPreference;
import java.util.ArrayList;
import java.util.List;
/**
* Updates the DND Settings conversations image resource based on the conversations channels.
*/
public class ZenModeConversationsImagePreferenceController
extends AbstractZenModePreferenceController {
private static final int MAX_CONVERSATIONS_SHOWN = 5;
private final int mIconSizePx;
private final int mIconOffsetPx;
private final ArrayList<Drawable> mConversationDrawables = new ArrayList<>();
private final NotificationBackend mNotificationBackend;
private ViewGroup mViewGroup;
private LayoutPreference mPreference;
public ZenModeConversationsImagePreferenceController(Context context, String key,
Lifecycle lifecycle, NotificationBackend notificationBackend) {
super(context, key, lifecycle);
mNotificationBackend = notificationBackend;
mIconSizePx =
mContext.getResources().getDimensionPixelSize(R.dimen.zen_conversations_icon_size);
mIconOffsetPx = mContext.getResources()
.getDimensionPixelSize(R.dimen.zen_conversations_icon_offset);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = (LayoutPreference) screen.findPreference(KEY);
mViewGroup =
(ViewGroup) mPreference.findViewById(R.id.zen_mode_settings_senders_overlay_view);
loadConversations();
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return KEY;
}
@Override
public void updateState(Preference preference) {
loadConversations();
mViewGroup.removeAllViews();
final int conversationSenders = mBackend.getPriorityConversationSenders();
if (conversationSenders == CONVERSATION_SENDERS_ANYONE) {
mViewGroup.setContentDescription(
mContext.getResources().getString(R.string.zen_mode_from_all_conversations));
} else if (conversationSenders == CONVERSATION_SENDERS_IMPORTANT) {
mViewGroup.setContentDescription(
mContext.getResources().getString(
R.string.zen_mode_from_important_conversations));
} else {
mViewGroup.setContentDescription(null);
mViewGroup.setVisibility(View.GONE);
return;
}
final int numDrawablesToShow = Math.min(MAX_CONVERSATIONS_SHOWN,
mConversationDrawables.size());
for (int i = 0; i < numDrawablesToShow; i++) {
ImageView iv = new ImageView(mContext);
iv.setImageDrawable(mConversationDrawables.get(i));
iv.setLayoutParams(new ViewGroup.LayoutParams(mIconSizePx, mIconSizePx));
FrameLayout fl = new FrameLayout(mContext);
fl.addView(iv);
fl.setPadding((numDrawablesToShow - i - 1) * mIconOffsetPx, 0, 0, 0);
mViewGroup.addView(fl);
}
mViewGroup.setVisibility(numDrawablesToShow > 0 ? View.VISIBLE : View.GONE);
}
private void loadConversations() {
// Load conversations
new AsyncTask<Void, Void, Void>() {
private List<Drawable> mDrawables = new ArrayList<>();
@Override
protected Void doInBackground(Void... unused) {
mDrawables.clear();
final int conversationSenders = mBackend.getPriorityConversationSenders();
if (conversationSenders == CONVERSATION_SENDERS_NONE) {
return null;
}
ParceledListSlice<ConversationChannelWrapper> conversations =
mNotificationBackend.getConversations(
conversationSenders == CONVERSATION_SENDERS_IMPORTANT);
if (conversations != null) {
for (ConversationChannelWrapper conversation : conversations.getList()) {
if (!conversation.getNotificationChannel().isDemoted()) {
Drawable drawable = mNotificationBackend.getConversationDrawable(
mContext,
conversation.getShortcutInfo(),
conversation.getPkg(),
conversation.getUid(),
conversation.getNotificationChannel()
.isImportantConversation());
if (drawable != null) {
mDrawables.add(drawable);
}
}
}
}
return null;
}
@Override
protected void onPostExecute(Void unused) {
if (mContext == null) {
return;
}
mConversationDrawables.clear();
mConversationDrawables.addAll(mDrawables);
updateState(mPreference);
}
}.execute();
}
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright (C) 2020 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.zen;
import android.app.NotificationManager;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settingslib.core.lifecycle.Lifecycle;
/**
* Controls the summary for preference found at:
* Settings > Sound > Do Not Disturb > People > Conversations
*/
public class ZenModeConversationsPreferenceController extends AbstractZenModePreferenceController {
private final ZenModeBackend mBackend;
private Preference mPreference;
public ZenModeConversationsPreferenceController(Context context,
String key, Lifecycle lifecycle) {
super(context, key, lifecycle);
mBackend = ZenModeBackend.getInstance(context);
}
@Override
public String getPreferenceKey() {
return KEY;
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(KEY);
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
switch (getZenMode()) {
case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
case Settings.Global.ZEN_MODE_ALARMS:
mPreference.setEnabled(false);
mPreference.setSummary(mBackend.getAlarmsTotalSilencePeopleSummary(
NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS));
break;
default:
preference.setEnabled(true);
preference.setSummary(mBackend.getConversationSummary());
}
}
}

View File

@@ -1,76 +0,0 @@
/*
* Copyright (C) 2020 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.zen;
import android.app.settings.SettingsEnums;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.List;
/**
* Settings > Sound > Do Not Disturb > Conversations
*/
@SearchIndexable
public class ZenModeConversationsSettings extends ZenModeSettingsBase {
private final NotificationBackend mNotificationBackend = new NotificationBackend();
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context, getSettingsLifecycle(), mNotificationBackend);
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Lifecycle lifecycle, NotificationBackend notificationBackend) {
List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new ZenModeConversationsImagePreferenceController(context,
"zen_mode_conversations_image", lifecycle, notificationBackend));
controllers.add(new ZenModePriorityConversationsPreferenceController(context,
"zen_mode_conversations_radio_buttons", lifecycle, notificationBackend));
return controllers;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.zen_mode_conversations_settings;
}
@Override
public int getMetricsCategory() {
return SettingsEnums.DND_CONVERSATIONS;
}
/**
* For Search.
*/
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.zen_mode_conversations_settings) {
@Override
public List<AbstractPreferenceController> createPreferenceControllers(
Context context) {
return buildPreferenceControllers(context, null, null);
}
};
}

View File

@@ -1,219 +0,0 @@
/*
* Copyright (C) 2020 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.zen;
import android.app.NotificationManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.icu.text.MessageFormat;
import android.os.AsyncTask;
import android.service.notification.ConversationChannelWrapper;
import android.view.View;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.notification.app.ConversationListSettings;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* Options to choose the priority conversations that are allowed to bypass DND.
*/
public class ZenModePriorityConversationsPreferenceController
extends AbstractZenModePreferenceController {
private static final int UNSET = -1;
@VisibleForTesting static final String KEY_ALL = "conversations_all";
@VisibleForTesting static final String KEY_IMPORTANT = "conversations_important";
@VisibleForTesting static final String KEY_NONE = "conversations_none";
private final NotificationBackend mNotificationBackend;
private int mNumImportantConversations = UNSET;
private int mNumConversations = UNSET;
private PreferenceCategory mPreferenceCategory;
private List<SelectorWithWidgetPreference> mSelectorWithWidgetPreferences = new ArrayList<>();
private Context mPreferenceScreenContext;
public ZenModePriorityConversationsPreferenceController(Context context, String key,
Lifecycle lifecycle, NotificationBackend notificationBackend) {
super(context, key, lifecycle);
mNotificationBackend = notificationBackend;
}
@Override
public void displayPreference(PreferenceScreen screen) {
mPreferenceScreenContext = screen.getContext();
mPreferenceCategory = screen.findPreference(getPreferenceKey());
if (mPreferenceCategory.findPreference(KEY_ALL) == null) {
makeRadioPreference(KEY_ALL, R.string.zen_mode_from_all_conversations);
makeRadioPreference(KEY_IMPORTANT, R.string.zen_mode_from_important_conversations);
makeRadioPreference(KEY_NONE, R.string.zen_mode_from_no_conversations);
updateChannelCounts();
}
super.displayPreference(screen);
}
@Override
public void onResume() {
super.onResume();
updateChannelCounts();
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return KEY;
}
@Override
public void updateState(Preference preference) {
final int currSetting = mBackend.getPriorityConversationSenders();
for (SelectorWithWidgetPreference pref : mSelectorWithWidgetPreferences) {
pref.setChecked(keyToSetting(pref.getKey()) == currSetting);
pref.setSummary(getSummary(pref.getKey()));
}
}
private static int keyToSetting(String key) {
switch (key) {
case KEY_ALL:
return NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
case KEY_IMPORTANT:
return NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
default:
return NotificationManager.Policy.CONVERSATION_SENDERS_NONE;
}
}
private String getSummary(String key) {
int numConversations;
if (KEY_ALL.equals(key)) {
numConversations = mNumConversations;
} else if (KEY_IMPORTANT.equals(key)) {
numConversations = mNumImportantConversations;
} else {
return null;
}
if (numConversations == UNSET) {
return null;
} else {
MessageFormat msgFormat = new MessageFormat(
mContext.getString(R.string.zen_mode_conversations_count),
Locale.getDefault());
Map<String, Object> args = new HashMap<>();
args.put("count", numConversations);
return msgFormat.format(args);
}
}
private void updateChannelCounts() {
// Load conversations
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... unused) {
ParceledListSlice<ConversationChannelWrapper> allConversations =
mNotificationBackend.getConversations(false);
int numConversations = 0;
if (allConversations != null) {
for (ConversationChannelWrapper conversation : allConversations.getList()) {
if (!conversation.getNotificationChannel().isDemoted()) {
numConversations++;
}
}
}
mNumConversations = numConversations;
ParceledListSlice<ConversationChannelWrapper> impConversations =
mNotificationBackend.getConversations(true);
int numImportantConversations = 0;
if (impConversations != null) {
for (ConversationChannelWrapper conversation : impConversations.getList()) {
if (!conversation.getNotificationChannel().isDemoted()) {
numImportantConversations++;
}
}
}
mNumImportantConversations = numImportantConversations;
return null;
}
@Override
protected void onPostExecute(Void unused) {
if (mContext == null) {
return;
}
updateState(mPreferenceCategory);
}
}.execute();
}
private SelectorWithWidgetPreference makeRadioPreference(String key, int titleId) {
final SelectorWithWidgetPreference pref =
new SelectorWithWidgetPreference(mPreferenceCategory.getContext());
if (KEY_ALL.equals(key) || KEY_IMPORTANT.equals(key)) {
pref.setExtraWidgetOnClickListener(mConversationSettingsWidgetClickListener);
}
pref.setKey(key);
pref.setTitle(titleId);
pref.setOnClickListener(mRadioButtonClickListener);
mPreferenceCategory.addPreference(pref);
mSelectorWithWidgetPreferences.add(pref);
return pref;
}
private View.OnClickListener mConversationSettingsWidgetClickListener =
new View.OnClickListener() {
@Override
public void onClick(View v) {
new SubSettingLauncher(mPreferenceScreenContext)
.setDestination(ConversationListSettings.class.getName())
.setSourceMetricsCategory(SettingsEnums.DND_CONVERSATIONS)
.launch();
}
};
private SelectorWithWidgetPreference.OnClickListener mRadioButtonClickListener =
new SelectorWithWidgetPreference.OnClickListener() {
@Override
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
int selectedConversationSetting = keyToSetting(preference.getKey());
if (selectedConversationSetting != mBackend.getPriorityConversationSenders()) {
mBackend.saveConversationSenders(selectedConversationSetting);
}
}
};
}

View File

@@ -29,12 +29,15 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
/**
@@ -144,9 +147,33 @@ public class SettingsPanelActivity extends FragmentActivity {
window.setGravity(Gravity.BOTTOM);
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT);
setupNavigationBar();
mPanelFragment = new PanelFragment();
mPanelFragment.setArguments(new Bundle(mBundle));
fragmentManager.beginTransaction().add(R.id.main_content, mPanelFragment).commit();
}
}
/**
* Adjust bottom edge and color.
*/
private void setupNavigationBar() {
// Extend the panel all the way to the bottom of the screen, as opposed to sitting on top of
// the navigation bar.
ViewCompat.setOnApplyWindowInsetsListener(getWindow().getDecorView(),
(v, windowInsets) -> {
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), 0);
return windowInsets; // propagate down to panel layout root element
});
// When using 3-button navigation in light mode, the system picks white navigation buttons
// which are not sufficiently contrasted from the panel background.
WindowInsetsControllerCompat windowInsetsController =
ViewCompat.getWindowInsetsController(getWindow().getDecorView());
if (windowInsetsController != null) {
boolean forceNavigationButtonsDark = !Utils.isNightMode(this);
windowInsetsController.setAppearanceLightNavigationBars(forceNavigationButtonsDark);
}
}
}

View File

@@ -23,6 +23,7 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.internal.app.LocaleHelper;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -53,9 +54,8 @@ public class NumberingPreferencesFragment extends DashboardFragment {
Log.w(getLogTag(), "No selected language.");
return "";
}
return Locale.forLanguageTag(selectedLanguage)
.stripExtensions()
.getDisplayName(Locale.forLanguageTag(selectedLanguage));
Locale locale = Locale.forLanguageTag(selectedLanguage);
return LocaleHelper.getDisplayName(locale.stripExtensions(), locale, true);
}
Log.w(getLogTag(), "Incorrect option : " + option);
return "";

View File

@@ -26,8 +26,6 @@ import android.os.Bundle;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
@@ -44,8 +42,6 @@ import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.List;
/** Tests for {@link BluetoothDetailsAudioRoutingFragment}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothUtils.class})
@@ -92,17 +88,6 @@ public class BluetoothDetailsAudioRoutingFragmentTest {
assertThat(mFragment.mCachedDevice.getAddress()).isEqualTo(TEST_ADDRESS);
}
@Test
public void getNonIndexableKeys_existInXmlLayout() {
final List<String> niks = BluetoothDetailsAudioRoutingFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(mContext);
final List<String> keys =
XmlTestUtils.getKeysFromPreferenceXml(mContext,
R.xml.bluetooth_audio_routing_fragment);
assertThat(keys).containsAtLeastElementsIn(niks);
}
private void setupEnvironment() {
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);

View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dream;
import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.util.ArraySet;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settingslib.dream.DreamBackend;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowContentResolver;
import org.robolectric.shadows.ShadowSettings;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowSettings.ShadowSecure.class})
public class DreamHomeControlsPreferenceControllerTest {
private Context mContext;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceScreen mScreen;
private DreamHomeControlsPreferenceController mController;
private SwitchPreference mPreference;
private DreamBackend mBackend;
private ShadowContentResolver mShadowContentResolver;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mShadowContentResolver = Shadow.extract(mContext.getContentResolver());
mBackend = new DreamBackend(mContext);
mController = new DreamHomeControlsPreferenceController(mContext, "key", mBackend);
mPreference = new SwitchPreference(mContext);
mPreference.setKey(mController.getPreferenceKey());
when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
mController.displayPreference(mScreen);
// Make home controls supported by default
mBackend.setSupportedComplications(
new ArraySet<>(new Integer[]{COMPLICATION_TYPE_HOME_CONTROLS}));
}
@After
public void tearDown() {
ShadowSettings.ShadowSecure.reset();
}
@Test
public void testSetChecked_setTrue_enablesSetting() {
mBackend.setHomeControlsEnabled(false);
assertThat(mBackend.getEnabledComplications())
.doesNotContain(COMPLICATION_TYPE_HOME_CONTROLS);
mController.setChecked(true);
assertThat(mBackend.getEnabledComplications())
.contains(COMPLICATION_TYPE_HOME_CONTROLS);
}
@Test
public void testSetChecked_setFalse_disablesSetting() {
mBackend.setHomeControlsEnabled(true);
assertThat(mBackend.getEnabledComplications())
.contains(COMPLICATION_TYPE_HOME_CONTROLS);
mController.setChecked(false);
assertThat(mBackend.getEnabledComplications())
.doesNotContain(COMPLICATION_TYPE_HOME_CONTROLS);
}
@Test
public void testIsChecked_returnsFalse() {
mBackend.setHomeControlsEnabled(false);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void testIsChecked_returnsTrue() {
mBackend.setHomeControlsEnabled(true);
assertThat(mBackend.getEnabledComplications())
.contains(COMPLICATION_TYPE_HOME_CONTROLS);
assertThat(mController.isChecked()).isTrue();
}
}

View File

@@ -19,14 +19,19 @@ package com.android.settings.notification;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.provider.Settings.Global;
import androidx.fragment.app.FragmentActivity;
@@ -72,6 +77,7 @@ public class DockAudioMediaPreferenceControllerTest {
mController = new DockAudioMediaPreferenceController(mContext, mSetting, null);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
doReturn(mScreen).when(mSetting).getPreferenceScreen();
fakeDockState(Intent.EXTRA_DOCK_STATE_LE_DESK);
}
@Test
@@ -90,6 +96,34 @@ public class DockAudioMediaPreferenceControllerTest {
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_undocked_shouldReturnFalse() {
when(mContext.registerReceiver(nullable(BroadcastReceiver.class),
any(IntentFilter.class))).thenReturn(null);
when(mContext.getResources().getBoolean(com.android.settings.R.bool.has_dock_settings))
.thenReturn(true);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_highEndDock_shouldReturnFalse() {
fakeDockState(Intent.EXTRA_DOCK_STATE_HE_DESK);
when(mContext.getResources().getBoolean(com.android.settings.R.bool.has_dock_settings))
.thenReturn(true);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_lowEndDock_shouldReturnTrue() {
fakeDockState(Intent.EXTRA_DOCK_STATE_LE_DESK);
when(mContext.getResources().getBoolean(com.android.settings.R.bool.has_dock_settings))
.thenReturn(true);
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void displayPreference_dockAudioDisabled_shouldSelectFirstItem() {
Global.putInt(mContentResolver, Global.DOCK_AUDIO_MEDIA_ENABLED, 0);
@@ -127,4 +161,11 @@ public class DockAudioMediaPreferenceControllerTest {
assertThat(Global.getInt(mContentResolver, Global.DOCK_AUDIO_MEDIA_ENABLED, 0))
.isEqualTo(1);
}
private void fakeDockState(int dockState) {
Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
intent.putExtra(Intent.EXTRA_DOCK_STATE, dockState);
when(mContext.registerReceiver(nullable(BroadcastReceiver.class),
any(IntentFilter.class))).thenReturn(intent);
}
}

View File

@@ -97,6 +97,7 @@ public class BadgePreferenceControllerTest {
@Test
public void testIsAvailable_notIfAppBlocked() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.channelCount = 1;
appRow.banned = true;
mController.onResume(appRow, mock(NotificationChannel.class), null, null, null, null, null);
assertFalse(mController.isAvailable());
@@ -105,6 +106,7 @@ public class BadgePreferenceControllerTest {
@Test
public void testIsAvailable_notIfChannelBlocked() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.channelCount = 1;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
mController.onResume(appRow, channel, null, null, null, null, null);
@@ -114,6 +116,7 @@ public class BadgePreferenceControllerTest {
@Test
public void testIsAvailable_channel_notIfAppOff() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.channelCount = 1;
appRow.showBadge = false;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
@@ -125,6 +128,7 @@ public class BadgePreferenceControllerTest {
@Test
public void testIsAvailable_notIfOffGlobally() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.channelCount = 1;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
@@ -136,16 +140,28 @@ public class BadgePreferenceControllerTest {
@Test
public void testIsAvailable_app() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.channelCount = 1;
mController.onResume(appRow, null, null, null, null, null, null);
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BADGING, 1);
assertTrue(mController.isAvailable());
}
@Test
public void testIsAvailable_appNoChannels() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.channelCount = 0;
mController.onResume(appRow, null, null, null, null, null, null);
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BADGING, 1);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_defaultChannel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = true;
appRow.channelCount = 1;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
@@ -159,6 +175,7 @@ public class BadgePreferenceControllerTest {
public void testIsAvailable_channel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = true;
appRow.channelCount = 1;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, null);
@@ -183,6 +200,7 @@ public class BadgePreferenceControllerTest {
public void testIsAvailable_filteredOut() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = true;
appRow.channelCount = 1;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null, new ArrayList<>());
@@ -195,6 +213,7 @@ public class BadgePreferenceControllerTest {
public void testIsAvailable_filteredIn() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = true;
appRow.channelCount = 1;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null,
@@ -206,9 +225,11 @@ public class BadgePreferenceControllerTest {
@Test
public void testUpdateState_disabledByAdmin() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.channelCount = 1;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getId()).thenReturn("something");
mController.onResume(new NotificationBackend.AppRow(), channel, null,
mController.onResume(appRow, channel, null,
null, null, mock(RestrictedLockUtils.EnforcedAdmin.class), null);
Preference pref = new RestrictedSwitchPreference(mContext);
@@ -220,6 +241,7 @@ public class BadgePreferenceControllerTest {
@Test
public void testUpdateState_channel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.channelCount = 1;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.canShowBadge()).thenReturn(true);
mController.onResume(appRow, channel, null, null, null, null, null);
@@ -240,6 +262,7 @@ public class BadgePreferenceControllerTest {
public void testUpdateState_app() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = true;
appRow.channelCount = 1;
mController.onResume(appRow, null, null, null, null, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
@@ -257,6 +280,7 @@ public class BadgePreferenceControllerTest {
public void testOnPreferenceChange_on_channel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = true;
appRow.channelCount = 1;
NotificationChannel channel =
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
channel.setShowBadge(false);
@@ -276,6 +300,7 @@ public class BadgePreferenceControllerTest {
public void testOnPreferenceChange_off_channel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = true;
appRow.channelCount = 1;
NotificationChannel channel =
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
channel.setShowBadge(true);
@@ -295,6 +320,7 @@ public class BadgePreferenceControllerTest {
public void testOnPreferenceChange_on_app() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = false;
appRow.channelCount = 1;
mController.onResume(appRow, null, null, null, null, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
@@ -312,6 +338,7 @@ public class BadgePreferenceControllerTest {
public void testOnPreferenceChange_off_app() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.showBadge = true;
appRow.channelCount = 1;
mController.onResume(appRow, null, null, null, null, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);

View File

@@ -1,170 +0,0 @@
/*
* Copyright (C) 2017 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.app;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
import android.os.UserManager;
import androidx.preference.Preference;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
@RunWith(RobolectricTestRunner.class)
public class DescriptionPreferenceControllerTest {
private Context mContext;
@Mock
private NotificationManager mNm;
@Mock
private UserManager mUm;
private DescriptionPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ShadowApplication shadowApplication = ShadowApplication.getInstance();
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
mContext = RuntimeEnvironment.application;
mController = spy(new DescriptionPreferenceController(mContext));
}
@Test
public void testNoCrashIfNoOnResume() {
mController.isAvailable();
mController.updateState(mock(Preference.class));
}
@Test
public void testIsAvailable_notIfNull() {
mController.onResume(null, null, null, null, null, null, null);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_notIfChannelGroupBlocked() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannelGroup group = mock(NotificationChannelGroup.class);
mController.onResume(appRow, null, group, null, null, null, null);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_notIfChannelBlocked() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_NONE);
mController.onResume(appRow, channel, null, null, null, null, null);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_notIfNoChannelDesc() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
mController.onResume(appRow, channel, null, null, null, null, null);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_notIfNoChannelGroupDesc() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannelGroup group = mock(NotificationChannelGroup.class);
mController.onResume(appRow, null, group, null, null, null, null);
assertFalse(mController.isAvailable());
}
@Test
public void testIsAvailable_channel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
when(channel.getDescription()).thenReturn("AAA");
mController.onResume(appRow, channel, null, null, null, null, null);
assertTrue(mController.isAvailable());
}
@Test
public void testIsAvailable_channelGroup() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannelGroup group = mock(NotificationChannelGroup.class);
when(group.getDescription()).thenReturn("something");
when(group.isBlocked()).thenReturn(false);
mController.onResume(appRow, null, group, null, null, null, null);
assertTrue(mController.isAvailable());
}
@Test
public void testIsAvailable_alwaysFiltered() {
assertFalse(mController.isIncludedInFilter());
}
@Test
public void testUpdateState_channel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_LOW);
when(channel.getDescription()).thenReturn("AAA");
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new Preference(RuntimeEnvironment.application);
mController.updateState(pref);
assertEquals("AAA", pref.getTitle());
assertFalse(pref.isEnabled());
assertFalse(pref.isSelectable());
}
@Test
public void testUpdateState_channelGroup() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannelGroup group = mock(NotificationChannelGroup.class);
when(group.getDescription()).thenReturn("something");
mController.onResume(appRow, null, group, null, null, null, null);
Preference pref = new Preference(RuntimeEnvironment.application);
mController.updateState(pref);
assertEquals("something", pref.getTitle());
assertFalse(pref.isEnabled());
assertFalse(pref.isSelectable());
}
}

View File

@@ -1,149 +0,0 @@
/*
* Copyright (C) 2020 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.zen;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_NONE;
import static com.android.settings.notification.zen.ZenModePriorityConversationsPreferenceController.KEY_ALL;
import static com.android.settings.notification.zen.ZenModePriorityConversationsPreferenceController.KEY_IMPORTANT;
import static com.android.settings.notification.zen.ZenModePriorityConversationsPreferenceController.KEY_NONE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class ZenModePriorityConversationsPreferenceControllerTest {
private ZenModePriorityConversationsPreferenceController mController;
@Mock
private ZenModeBackend mZenBackend;
@Mock
private PreferenceCategory mMockPrefCategory;
@Mock
private NotificationManager.Policy mPolicy;
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private NotificationBackend mNotifBackend;
private List<SelectorWithWidgetPreference> mSelectorWithWidgetPreferences;
private ContentResolver mContentResolver;
private Context mContext;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new ZenModePriorityConversationsPreferenceController(
mContext, "test_key", mock(Lifecycle.class), mNotifBackend);
ReflectionHelpers.setField(mController, "mBackend", mZenBackend);
when(mMockPrefCategory.getContext()).thenReturn(mContext);
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mMockPrefCategory);
captureRadioButtons();
}
@Test
public void displayPreference_radioButtonsCreatedOnlyOnce() {
when(mMockPrefCategory.findPreference(any())).thenReturn(mock(Preference.class));
// radio buttons were already created, so don't re-create them
mController.displayPreference(mPreferenceScreen);
verify(mMockPrefCategory, never()).addPreference(any());
}
@Test
public void clickAllConversations() {
SelectorWithWidgetPreference allConversationsRb = getButton(KEY_ALL);
allConversationsRb.onClick();
verify(mZenBackend).saveConversationSenders(CONVERSATION_SENDERS_ANYONE);
}
@Test
public void clickImportantConversations() {
SelectorWithWidgetPreference importantConversationsRb = getButton(KEY_IMPORTANT);
importantConversationsRb.onClick();
verify(mZenBackend).saveConversationSenders(CONVERSATION_SENDERS_IMPORTANT);
}
@Test
public void clickNoConversations() {
SelectorWithWidgetPreference noConversationsRb = getButton(KEY_NONE);
noConversationsRb.onClick();
verify(mZenBackend)
.saveConversationSenders(CONVERSATION_SENDERS_NONE);
}
private void captureRadioButtons() {
ArgumentCaptor<SelectorWithWidgetPreference> rbCaptor =
ArgumentCaptor.forClass(SelectorWithWidgetPreference.class);
mController.displayPreference(mPreferenceScreen);
// verifies 3 buttons were added
verify(mMockPrefCategory, times(3)).addPreference(rbCaptor.capture());
mSelectorWithWidgetPreferences = rbCaptor.getAllValues();
assertThat(mSelectorWithWidgetPreferences.size()).isEqualTo(3);
reset(mMockPrefCategory);
}
private SelectorWithWidgetPreference getButton(String key) {
for (SelectorWithWidgetPreference pref : mSelectorWithWidgetPreferences) {
if (key.equals(pref.getKey())) {
return pref;
}
}
return null;
}
}

View File

@@ -16,11 +16,13 @@
package com.android.settings.panel;
import static android.content.res.Configuration.UI_MODE_NIGHT_NO;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -30,15 +32,20 @@ import static org.mockito.Mockito.when;
import android.content.res.Configuration;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -61,6 +68,9 @@ public class SettingsPanelActivityTest {
private PanelFragment mPanelFragment;
@Mock
private FragmentManager mFragmentManager;
@Mock
private FragmentTransaction mTransaction;
private int mOriginalUiMode;
@Before
public void setUp() {
@@ -76,6 +86,15 @@ public class SettingsPanelActivityTest {
mSettingsPanelActivity.mPanelFragment = mPanelFragment;
when(mFragmentManager.findFragmentById(R.id.main_content)).thenReturn(mPanelFragment);
when(mSettingsPanelActivity.getSupportFragmentManager()).thenReturn(mFragmentManager);
mOriginalUiMode = mSettingsPanelActivity.getResources().getConfiguration().uiMode;
when(mFragmentManager.beginTransaction()).thenReturn(mTransaction);
when(mTransaction.add(anyInt(), any())).thenReturn(mTransaction);
when(mTransaction.commit()).thenReturn(0); // don't care about return value
}
@After
public void tearDown() {
mSettingsPanelActivity.getResources().getConfiguration().uiMode = mOriginalUiMode;
}
@Test
@@ -179,4 +198,24 @@ public class SettingsPanelActivityTest {
verify(mPanelFragment, never()).updatePanelWithAnimation();
}
@Test
public void onCreated_isWindowBottomPaddingZero() {
int paddingBottom = mSettingsPanelActivity.getWindow().getDecorView().getPaddingBottom();
assertThat(paddingBottom).isEqualTo(0);
}
@Test
public void notInNightMode_lightNavigationBarAppearance() {
Configuration config = mSettingsPanelActivity.getResources().getConfiguration();
config.uiMode = UI_MODE_NIGHT_NO;
mSettingsPanelActivity.onConfigurationChanged(config); // forces creation
mSettingsPanelActivity.onNewIntent(mSettingsPanelActivity.getIntent());
verify(mFragmentManager).beginTransaction();
View decorView = mSettingsPanelActivity.getWindow().getDecorView();
WindowInsetsControllerCompat controller = ViewCompat.getWindowInsetsController(decorView);
assertThat(controller.isAppearanceLightNavigationBars()).isTrue();
}
}

View File

@@ -46,6 +46,7 @@ import org.junit.runner.RunWith;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@@ -55,6 +56,13 @@ public class CredentialManagerPreferenceControllerTest {
private PreferenceScreen mScreen;
private PreferenceCategory mCredentialsPreferenceCategory;
private static final String TEST_PACKAGE_NAME_A = "com.android.providerA";
private static final String TEST_PACKAGE_NAME_B = "com.android.providerB";
private static final String TEST_PACKAGE_NAME_C = "com.android.providerC";
private static final String TEST_TITLE_APP_A = "test app A";
private static final String TEST_TITLE_APP_B = "test app B";
private static final String TEST_TITLE_SERVICE_C = "test service C1";
@Before
public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext());
@@ -114,10 +122,10 @@ public class CredentialManagerPreferenceControllerTest {
@Test
public void buildSwitchPreference() {
CredentialProviderInfo providerInfo1 =
createCredentialProviderInfo(
createCredentialProviderInfoWithIsEnabled(
"com.android.provider1", "ClassA", "Service Title", false);
CredentialProviderInfo providerInfo2 =
createCredentialProviderInfo(
createCredentialProviderInfoWithIsEnabled(
"com.android.provider2", "ClassA", "Service Title", false);
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
@@ -217,10 +225,10 @@ public class CredentialManagerPreferenceControllerTest {
@Test
public void handlesCredentialProviderInfoEnabledDisabled() {
CredentialProviderInfo providerInfo1 =
createCredentialProviderInfo(
createCredentialProviderInfoWithIsEnabled(
"com.android.provider1", "ClassA", "Service Title", false);
CredentialProviderInfo providerInfo2 =
createCredentialProviderInfo(
createCredentialProviderInfoWithIsEnabled(
"com.android.provider2", "ClassA", "Service Title", true);
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
@@ -244,6 +252,63 @@ public class CredentialManagerPreferenceControllerTest {
assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue();
}
@Test
public void displayPreference_withServices_preferencesAdded_sameAppShouldBeMerged() {
CredentialProviderInfo serviceA1 =
createCredentialProviderInfoWithAppLabel(
TEST_PACKAGE_NAME_A,
"CredManProviderA1",
TEST_TITLE_APP_A,
"test service A1");
CredentialProviderInfo serviceB1 =
createCredentialProviderInfoWithAppLabel(
TEST_PACKAGE_NAME_B,
"CredManProviderB1",
TEST_TITLE_APP_B,
"test service B");
CredentialProviderInfo serviceC1 =
createCredentialProviderInfoWithAppLabel(
TEST_PACKAGE_NAME_C,
"CredManProviderC1",
"test app C1",
TEST_TITLE_SERVICE_C);
CredentialProviderInfo serviceC2 =
createCredentialProviderInfoWithAppLabel(
TEST_PACKAGE_NAME_C,
"CredManProviderC2",
"test app C2",
TEST_TITLE_SERVICE_C);
CredentialProviderInfo serviceC3 =
createCredentialProviderInfoBuilder(
TEST_PACKAGE_NAME_C,
"CredManProviderC3",
"test app C3",
TEST_TITLE_SERVICE_C)
.setEnabled(true)
.build();
CredentialManagerPreferenceController controller =
createControllerWithServices(
Lists.newArrayList(serviceA1, serviceB1, serviceC1, serviceC2, serviceC3));
controller.displayPreference(mScreen);
assertThat(controller.isConnected()).isFalse();
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(3);
Map<String, SwitchPreference> prefs =
controller.buildPreferenceList(mContext, mCredentialsPreferenceCategory);
assertThat(prefs.size()).isEqualTo(3);
assertThat(prefs.containsKey(TEST_PACKAGE_NAME_A)).isTrue();
assertThat(prefs.get(TEST_PACKAGE_NAME_A).getTitle()).isEqualTo(TEST_TITLE_APP_A);
assertThat(prefs.get(TEST_PACKAGE_NAME_A).isChecked()).isFalse();
assertThat(prefs.containsKey(TEST_PACKAGE_NAME_B)).isTrue();
assertThat(prefs.get(TEST_PACKAGE_NAME_B).getTitle()).isEqualTo(TEST_TITLE_APP_B);
assertThat(prefs.get(TEST_PACKAGE_NAME_B).isChecked()).isFalse();
assertThat(prefs.containsKey(TEST_PACKAGE_NAME_C)).isTrue();
assertThat(prefs.get(TEST_PACKAGE_NAME_C).getTitle()).isEqualTo(TEST_TITLE_SERVICE_C);
assertThat(prefs.get(TEST_PACKAGE_NAME_C).isChecked()).isTrue();
}
private CredentialManagerPreferenceController createControllerWithServices(
List<CredentialProviderInfo> availableServices) {
CredentialManagerPreferenceController controller =
@@ -259,23 +324,34 @@ public class CredentialManagerPreferenceControllerTest {
private CredentialProviderInfo createCredentialProviderInfo(
String packageName, String className) {
return createCredentialProviderInfo(packageName, className, null, false);
return createCredentialProviderInfoBuilder(packageName, className, null, "App Name")
.build();
}
private CredentialProviderInfo createCredentialProviderInfo(
String packageName, String className, CharSequence label, boolean isEnabled) {
ServiceInfo si = new ServiceInfo();
si.packageName = packageName;
si.name = className;
si.nonLocalizedLabel = "test";
si.applicationInfo = new ApplicationInfo();
si.applicationInfo.packageName = packageName;
si.applicationInfo.nonLocalizedLabel = "test";
return new CredentialProviderInfo.Builder(si)
.setOverrideLabel(label)
private CredentialProviderInfo createCredentialProviderInfoWithIsEnabled(
String packageName, String className, CharSequence serviceLabel, boolean isEnabled) {
return createCredentialProviderInfoBuilder(packageName, className, serviceLabel, "App Name")
.setEnabled(isEnabled)
.build();
}
private CredentialProviderInfo createCredentialProviderInfoWithAppLabel(
String packageName, String className, CharSequence serviceLabel, String appLabel) {
return createCredentialProviderInfoBuilder(packageName, className, serviceLabel, appLabel)
.build();
}
private CredentialProviderInfo.Builder createCredentialProviderInfoBuilder(
String packageName, String className, CharSequence serviceLabel, String appLabel) {
ServiceInfo si = new ServiceInfo();
si.packageName = packageName;
si.name = className;
si.nonLocalizedLabel = serviceLabel;
si.applicationInfo = new ApplicationInfo();
si.applicationInfo.packageName = packageName;
si.applicationInfo.nonLocalizedLabel = appLabel;
return new CredentialProviderInfo.Builder(si).setOverrideLabel(serviceLabel);
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.language;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.FeatureFlagUtils;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.Settings;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class LanguagePreferenceControllerTest {
private boolean mCacheFeatureFlagSwitch = false;
private Context mContext;
private LanguagePreferenceController mController;
@Before
public void setup() {
mContext = ApplicationProvider.getApplicationContext();
mCacheFeatureFlagSwitch =
FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
mController = new LanguagePreferenceController(mContext, "key");
}
@After
public void tearDown() {
FeatureFlagUtils.setEnabled(
mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI, mCacheFeatureFlagSwitch);
}
@Test
public void getAvailabilityStatus_featureFlagOff_returnUnavailable() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI,
false);
int result = mController.getAvailabilityStatus();
assertEquals(CONDITIONALLY_UNAVAILABLE, result);
}
@Test
public void getAvailabilityStatus_featureFlagOff_LanguageAndInputSettingsActivityEnabled() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI,
false);
mController.getAvailabilityStatus();
assertTrue(isActivityEnable(mContext, Settings.LanguageAndInputSettingsActivity.class));
assertFalse(isActivityEnable(mContext, Settings.LanguageSettingsActivity.class));
}
@Test
public void getAvailabilityStatus_featureFlagOff_LanguageAndInputSettingsActivitydisabled() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI,
true);
mController.getAvailabilityStatus();
assertFalse(isActivityEnable(mContext, Settings.LanguageAndInputSettingsActivity.class));
assertTrue(isActivityEnable(mContext, Settings.LanguageSettingsActivity.class));
}
private static boolean isActivityEnable(Context context, Class klazz) {
PackageManager packageManager = context.getPackageManager();
ComponentName componentName =
new ComponentName(context, klazz);
int flag = packageManager.getComponentEnabledSetting(componentName);
return flag == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
}
}

View File

@@ -28,9 +28,11 @@ import android.app.ProgressDialog;
import android.content.Context;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.lifecycle.Lifecycle;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -61,6 +63,10 @@ public class AutoSelectPreferenceControllerTest {
private CarrierConfigCache mCarrierConfigCache;
@Mock
private ProgressDialog mProgressDialog;
@Mock
private ServiceState mTestServiceState;
@Mock
private Lifecycle mLifecycle;
private PersistableBundle mCarrierConfig;
private AutoSelectPreferenceController mController;
@@ -88,7 +94,16 @@ public class AutoSelectPreferenceControllerTest {
mController = new AutoSelectPreferenceController(mContext, "auto_select");
mController.mProgressDialog = mProgressDialog;
mController.mSwitchPreference = mSwitchPreference;
mController.init(SUB_ID);
mController.init(mLifecycle, SUB_ID);
sleepAfterInit();
}
private void sleepAfterInit() {
try {
Thread.sleep(2000);
} catch (Exception e) {
fail("Sleep timeout " + e);
}
}
@Test
@@ -111,7 +126,8 @@ public class AutoSelectPreferenceControllerTest {
@Test
public void updateState_isRoaming_enabled() {
when(mTelephonyManager.getServiceState().getRoaming()).thenReturn(true);
when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState);
when(mTestServiceState.getRoaming()).thenReturn(true);
mController.updateState(mSwitchPreference);
@@ -120,7 +136,8 @@ public class AutoSelectPreferenceControllerTest {
@Test
public void updateState_notRoamingWithAutoSelectOn_disabled() {
when(mTelephonyManager.getServiceState().getRoaming()).thenReturn(false);
when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState);
when(mTestServiceState.getRoaming()).thenReturn(false);
doReturn(OPERATOR_NAME).when(mTelephonyManager).getSimOperatorName();
mController.updateState(mSwitchPreference);
@@ -136,6 +153,34 @@ public class AutoSelectPreferenceControllerTest {
when(mCarrierConfigCache.getConfigForSubId(SUB_ID)).thenReturn(null);
// Should not crash
mController.init(SUB_ID);
mController.init(mLifecycle, SUB_ID);
}
@Test
public void updateUiAutoSelectValue_serviceStateGetIsManualSelection_isCheckedFalse() {
when(mTelephonyManager.getNetworkSelectionMode()).thenReturn(
TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
when(mTestServiceState.getIsManualSelection()).thenReturn(true);
mController.init(mLifecycle, SUB_ID);
sleepAfterInit();
mController.updateUiAutoSelectValue(mTestServiceState);
assertThat(mController.isChecked()).isFalse();
assertThat(mSwitchPreference.isChecked()).isFalse();
}
@Test
public void updateUiAutoSelectValue_serviceStateGetIsAutoSelection_isCheckedTrue() {
when(mTelephonyManager.getNetworkSelectionMode()).thenReturn(
TelephonyManager.NETWORK_SELECTION_MODE_MANUAL);
when(mTestServiceState.getIsManualSelection()).thenReturn(false);
mController.init(mLifecycle, SUB_ID);
sleepAfterInit();
mController.updateUiAutoSelectValue(mTestServiceState);
assertThat(mController.isChecked()).isTrue();
assertThat(mSwitchPreference.isChecked()).isTrue();
}
}