Snap for 12253386 from 8cd5a449dd
to 24Q4-release
Change-Id: I5b47fd5716b18fbd495d8155c37d15274e3e1036
This commit is contained in:
@@ -44,7 +44,7 @@
|
|||||||
style="@style/TextAppearance.SearchBar"
|
style="@style/TextAppearance.SearchBar"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
android:text="@string/homepage_search"/>
|
android:text="@string/homepage_search"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@@ -69,7 +69,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingVertical="8dp"
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||||
|
|
||||||
|
@@ -1864,6 +1864,10 @@
|
|||||||
<string name="device_details_title">Device details</string>
|
<string name="device_details_title">Device details</string>
|
||||||
<!-- Title for keyboard settings preferences. [CHAR LIMIT=50] -->
|
<!-- Title for keyboard settings preferences. [CHAR LIMIT=50] -->
|
||||||
<string name="bluetooth_device_keyboard_settings_preference_title">Keyboard settings</string>
|
<string name="bluetooth_device_keyboard_settings_preference_title">Keyboard settings</string>
|
||||||
|
<!-- Title for more settings preferences. [CHAR LIMIT=50] -->
|
||||||
|
<string name="bluetooth_device_more_settings_preference_title">More settings</string>
|
||||||
|
<!-- Title for more settings summary. [CHAR LIMIT=50] -->
|
||||||
|
<string name="bluetooth_device_more_settings_preference_summary">Firmware updates, about, and more</string>
|
||||||
<!-- Title of the item to show device MAC address -->
|
<!-- Title of the item to show device MAC address -->
|
||||||
<string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string>
|
<string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string>
|
||||||
<!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->
|
<!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->
|
||||||
@@ -1884,6 +1888,9 @@
|
|||||||
<!-- Bluetooth device details companion apps. In the confirmation dialog for removing an associated app, this is the label on the button that will complete the disassociate action. [CHAR LIMIT=80] -->
|
<!-- Bluetooth device details companion apps. In the confirmation dialog for removing an associated app, this is the label on the button that will complete the disassociate action. [CHAR LIMIT=80] -->
|
||||||
<string name = "bluetooth_companion_app_remove_association_confirm_button">Disconnect app</string>
|
<string name = "bluetooth_companion_app_remove_association_confirm_button">Disconnect app</string>
|
||||||
|
|
||||||
|
<!-- Title of device details screen [CHAR LIMIT=28]-->
|
||||||
|
<string name="device_details_more_settings">More settings</string>
|
||||||
|
|
||||||
<!-- Bluetooth developer settings: Maximum number of connected audio devices -->
|
<!-- Bluetooth developer settings: Maximum number of connected audio devices -->
|
||||||
<string name="bluetooth_max_connected_audio_devices_string">Maximum connected Bluetooth audio devices</string>
|
<string name="bluetooth_max_connected_audio_devices_string">Maximum connected Bluetooth audio devices</string>
|
||||||
<!-- Bluetooth developer settings: Maximum number of connected audio devices -->
|
<!-- Bluetooth developer settings: Maximum number of connected audio devices -->
|
||||||
@@ -4493,10 +4500,10 @@
|
|||||||
<string name="trackpad_reverse_scrolling_title">Reverse scrolling</string>
|
<string name="trackpad_reverse_scrolling_title">Reverse scrolling</string>
|
||||||
<!-- Summary text for 'Reverse scrolling' [CHAR LIMIT=60] -->
|
<!-- Summary text for 'Reverse scrolling' [CHAR LIMIT=60] -->
|
||||||
<string name="trackpad_reverse_scrolling_summary">Content moves up when you scroll down</string>
|
<string name="trackpad_reverse_scrolling_summary">Content moves up when you scroll down</string>
|
||||||
<!-- Title text for 'Bottom-right tap' [CHAR LIMIT=35] -->
|
<!-- Title text for 'Bottom-right click', a setting that allows the user to right-click by pressing in the bottom-right corner of a touchpad. [CHAR LIMIT=35] -->
|
||||||
<string name="trackpad_bottom_right_tap_title">Bottom-right tap</string>
|
<string name="trackpad_bottom_right_tap_title">Bottom-right click</string>
|
||||||
<!-- Summary text for 'Bottom-right tap' [CHAR LIMIT=60] -->
|
<!-- Summary text for 'Bottom-right click', a setting that allows the user to right-click by pressing in the bottom-right corner of a touchpad [CHAR LIMIT=60] -->
|
||||||
<string name="trackpad_bottom_right_tap_summary">Tap the bottom right corner of the touchpad for more options</string>
|
<string name="trackpad_bottom_right_tap_summary">Click in the bottom right corner of the touchpad for more options</string>
|
||||||
<!-- Title text for 'Pointer speed'. [CHAR LIMIT=35] -->
|
<!-- Title text for 'Pointer speed'. [CHAR LIMIT=35] -->
|
||||||
<string name="trackpad_pointer_speed">Pointer speed</string>
|
<string name="trackpad_pointer_speed">Pointer speed</string>
|
||||||
<!-- Title text for mouse pointer fill style. [CHAR LIMIT=35] -->
|
<!-- Title text for mouse pointer fill style. [CHAR LIMIT=35] -->
|
||||||
@@ -8184,10 +8191,10 @@
|
|||||||
other {{effect_1}, {effect_2}, and # more}
|
other {{effect_1}, {effect_2}, and # more}
|
||||||
}
|
}
|
||||||
</string>
|
</string>
|
||||||
<!-- Modes: setting for whether the mode should filter (silence/hide) notifications/volume streams -->
|
<!-- Modes: setting for a mode to allow all notifications and sounds through -->
|
||||||
<string name="mode_notification_filter_title">Limit what can notify you</string>
|
<string name="zen_mode_allow_all_notifications">Allow all notifications</string>
|
||||||
<!-- Modes: subtext when a mode is not filtering (silence/hide) notifications/volume streams -->
|
<!-- Modes: subtext when a mode is allowing all notifications and sounds (i.e. no filtering) -->
|
||||||
<string name="mode_no_notification_filter">No interruptions are filtered</string>
|
<string name="zen_mode_all_notifications_allowed">People, apps, and sounds can interrupt</string>
|
||||||
|
|
||||||
<!-- Do not disturb: restrict notifications settings title [CHAR LIMIT=80] -->
|
<!-- Do not disturb: restrict notifications settings title [CHAR LIMIT=80] -->
|
||||||
<string name="zen_mode_restrict_notifications_title">Display options for filtered
|
<string name="zen_mode_restrict_notifications_title">Display options for filtered
|
||||||
|
24
res/xml/bluetooth_device_more_settings_fragment.xml
Normal file
24
res/xml/bluetooth_device_more_settings_fragment.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2024 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:key="bluetooth_device_more_settings_screen"
|
||||||
|
android:title="@string/device_details_more_settings">
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="bluetooth_profiles"/>
|
||||||
|
</PreferenceScreen>
|
@@ -176,12 +176,11 @@
|
|||||||
settings:searchable="false"
|
settings:searchable="false"
|
||||||
settings:controller="com.android.settings.network.telephony.EnabledNetworkModePreferenceController"/>
|
settings:controller="com.android.settings.network.telephony.EnabledNetworkModePreferenceController"/>
|
||||||
|
|
||||||
|
<!-- Settings search is handled by CarrierSettingsVersionSearchItem. -->
|
||||||
<Preference
|
<Preference
|
||||||
android:key="carrier_settings_version_key"
|
android:key="carrier_settings_version_key"
|
||||||
android:title="@string/carrier_settings_version"
|
android:title="@string/carrier_settings_version"
|
||||||
android:enabled="false"
|
settings:searchable="false"
|
||||||
android:shouldDisableView="false"
|
|
||||||
android:selectable="false"
|
|
||||||
settings:controller="com.android.settings.network.telephony.CarrierSettingsVersionPreferenceController"
|
settings:controller="com.android.settings.network.telephony.CarrierSettingsVersionPreferenceController"
|
||||||
settings:enableCopying="true"/>
|
settings:enableCopying="true"/>
|
||||||
|
|
||||||
|
@@ -59,8 +59,8 @@
|
|||||||
android:key="modes_filters">
|
android:key="modes_filters">
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="allow_filtering"
|
android:key="allow_all"
|
||||||
android:title="@string/mode_notification_filter_title"/>
|
android:title="@string/zen_mode_allow_all_notifications"/>
|
||||||
|
|
||||||
<com.android.settings.notification.modes.CircularIconsPreference
|
<com.android.settings.notification.modes.CircularIconsPreference
|
||||||
android:key="zen_mode_people"
|
android:key="zen_mode_people"
|
||||||
|
@@ -48,6 +48,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.bluetooth.ui.model.FragmentTypeModel;
|
||||||
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
|
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
|
||||||
import com.android.settings.connecteddevice.stylus.StylusDevicesController;
|
import com.android.settings.connecteddevice.stylus.StylusDevicesController;
|
||||||
import com.android.settings.core.SettingsUIDeviceConfig;
|
import com.android.settings.core.SettingsUIDeviceConfig;
|
||||||
@@ -255,8 +256,17 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
|||||||
public void onDetach() {
|
public void onDetach() {
|
||||||
super.onDetach();
|
super.onDetach();
|
||||||
mManager.getEventManager().unregisterCallback(mBluetoothCallback);
|
mManager.getEventManager().unregisterCallback(mBluetoothCallback);
|
||||||
|
BluetoothDevice device = mCachedDevice.getDevice();
|
||||||
|
try {
|
||||||
mBluetoothAdapter.removeOnMetadataChangedListener(
|
mBluetoothAdapter.removeOnMetadataChangedListener(
|
||||||
mCachedDevice.getDevice(), mExtraControlMetadataListener);
|
device, mExtraControlMetadataListener);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.w(
|
||||||
|
TAG,
|
||||||
|
"Unable to unregister metadata change callback for "
|
||||||
|
+ mCachedDevice,
|
||||||
|
e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateExtraControlUri(int viewWidth) {
|
private void updateExtraControlUri(int viewWidth) {
|
||||||
@@ -343,7 +353,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
|||||||
public void onCreatePreferences(@NonNull Bundle savedInstanceState, @NonNull String rootKey) {
|
public void onCreatePreferences(@NonNull Bundle savedInstanceState, @NonNull String rootKey) {
|
||||||
super.onCreatePreferences(savedInstanceState, rootKey);
|
super.onCreatePreferences(savedInstanceState, rootKey);
|
||||||
if (Flags.enableBluetoothDeviceDetailsPolish()) {
|
if (Flags.enableBluetoothDeviceDetailsPolish()) {
|
||||||
mFormatter.updateLayout();
|
mFormatter.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +410,9 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
|||||||
@Override
|
@Override
|
||||||
protected void addPreferenceController(AbstractPreferenceController controller) {
|
protected void addPreferenceController(AbstractPreferenceController controller) {
|
||||||
if (Flags.enableBluetoothDeviceDetailsPolish()) {
|
if (Flags.enableBluetoothDeviceDetailsPolish()) {
|
||||||
List<String> keys = mFormatter.getVisiblePreferenceKeysForMainPage();
|
List<String> keys =
|
||||||
|
mFormatter.getVisiblePreferenceKeys(
|
||||||
|
FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
|
||||||
Lifecycle lifecycle = getSettingsLifecycle();
|
Lifecycle lifecycle = getSettingsLifecycle();
|
||||||
if (keys == null || keys.contains(controller.getPreferenceKey())) {
|
if (keys == null || keys.contains(controller.getPreferenceKey())) {
|
||||||
super.addPreferenceController(controller);
|
super.addPreferenceController(controller);
|
||||||
|
@@ -66,15 +66,14 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
|
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
|
||||||
import com.android.settings.bluetooth.ui.composable.Icon as DeviceSettingComposeIcon
|
import com.android.settings.bluetooth.ui.composable.Icon as DeviceSettingComposeIcon
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
|
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
|
|
||||||
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
||||||
import com.android.settingslib.spa.widget.dialog.getDialogWidth
|
import com.android.settingslib.spa.widget.dialog.getDialogWidth
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MultiTogglePreferenceGroup(
|
fun MultiTogglePreferenceGroup(
|
||||||
preferenceModels: List<DeviceSettingModel.MultiTogglePreference>,
|
preferenceModels: List<DeviceSettingPreferenceModel.MultiTogglePreference>,
|
||||||
) {
|
) {
|
||||||
var settingIdForPopUp by remember { mutableStateOf<Int?>(null) }
|
var settingIdForPopUp by remember { mutableStateOf<Int?>(null) }
|
||||||
|
|
||||||
@@ -115,7 +114,7 @@ fun MultiTogglePreferenceGroup(
|
|||||||
colors = getButtonColors(preferenceModel.isActive),
|
colors = getButtonColors(preferenceModel.isActive),
|
||||||
contentPadding = PaddingValues(0.dp)) {
|
contentPadding = PaddingValues(0.dp)) {
|
||||||
DeviceSettingComposeIcon(
|
DeviceSettingComposeIcon(
|
||||||
preferenceModel.toggles[preferenceModel.state.selectedIndex]
|
preferenceModel.toggles[preferenceModel.selectedIndex]
|
||||||
.icon,
|
.icon,
|
||||||
modifier = Modifier.size(24.dp))
|
modifier = Modifier.size(24.dp))
|
||||||
}
|
}
|
||||||
@@ -144,7 +143,7 @@ private fun getButtonColors(isActive: Boolean) =
|
|||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun dialog(
|
private fun dialog(
|
||||||
multiTogglePreference: DeviceSettingModel.MultiTogglePreference,
|
multiTogglePreference: DeviceSettingPreferenceModel.MultiTogglePreference,
|
||||||
onDismiss: () -> Unit
|
onDismiss: () -> Unit
|
||||||
) {
|
) {
|
||||||
BasicAlertDialog(
|
BasicAlertDialog(
|
||||||
@@ -179,7 +178,7 @@ private fun dialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiTogglePreference) {
|
private fun dialogContent(multiTogglePreference: DeviceSettingPreferenceModel.MultiTogglePreference) {
|
||||||
Column {
|
Column {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().height(24.dp),
|
modifier = Modifier.fillMaxWidth().height(24.dp),
|
||||||
@@ -219,7 +218,7 @@ private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiToggleP
|
|||||||
}
|
}
|
||||||
Row {
|
Row {
|
||||||
for ((idx, toggle) in multiTogglePreference.toggles.withIndex()) {
|
for ((idx, toggle) in multiTogglePreference.toggles.withIndex()) {
|
||||||
val selected = idx == multiTogglePreference.state.selectedIndex
|
val selected = idx == multiTogglePreference.selectedIndex
|
||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.weight(1f)
|
Modifier.weight(1f)
|
||||||
@@ -237,8 +236,7 @@ private fun dialogContent(multiTogglePreference: DeviceSettingModel.MultiToggleP
|
|||||||
) {
|
) {
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
multiTogglePreference.updateState(
|
multiTogglePreference.onSelectedChange(idx)
|
||||||
DeviceSettingStateModel.MultiTogglePreferenceState(idx))
|
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
colors =
|
colors =
|
||||||
|
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.bluetooth.ui.model
|
||||||
|
|
||||||
|
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
|
||||||
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
|
||||||
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
|
||||||
|
|
||||||
|
/** Models a device setting preference. */
|
||||||
|
sealed interface DeviceSettingPreferenceModel {
|
||||||
|
@DeviceSettingId
|
||||||
|
val id: Int
|
||||||
|
|
||||||
|
/** Models a plain preference. */
|
||||||
|
data class PlainPreference(
|
||||||
|
@DeviceSettingId override val id: Int,
|
||||||
|
val title: String,
|
||||||
|
val summary: String? = null,
|
||||||
|
val icon: DeviceSettingIcon? = null,
|
||||||
|
val onClick: (() -> Unit)? = null,
|
||||||
|
) : DeviceSettingPreferenceModel
|
||||||
|
|
||||||
|
/** Models a switch preference. */
|
||||||
|
data class SwitchPreference(
|
||||||
|
@DeviceSettingId override val id: Int,
|
||||||
|
val title: String,
|
||||||
|
val summary: String? = null,
|
||||||
|
val icon: DeviceSettingIcon? = null,
|
||||||
|
val checked: Boolean,
|
||||||
|
val onCheckedChange: ((Boolean) -> Unit),
|
||||||
|
val onPrimaryClick: (() -> Unit)? = null,
|
||||||
|
) : DeviceSettingPreferenceModel
|
||||||
|
|
||||||
|
/** Models a multi-toggle preference. */
|
||||||
|
data class MultiTogglePreference(
|
||||||
|
@DeviceSettingId override val id: Int,
|
||||||
|
val title: String,
|
||||||
|
val toggles: List<ToggleModel>,
|
||||||
|
val isActive: Boolean,
|
||||||
|
val selectedIndex: Int,
|
||||||
|
val isAllowedChangingState: Boolean,
|
||||||
|
val onSelectedChange: (Int) -> Unit,
|
||||||
|
) : DeviceSettingPreferenceModel
|
||||||
|
|
||||||
|
/** Models a footer preference. */
|
||||||
|
data class FooterPreference(
|
||||||
|
@DeviceSettingId override val id: Int,
|
||||||
|
val footerText: String,
|
||||||
|
) : DeviceSettingPreferenceModel
|
||||||
|
|
||||||
|
/** Models a preference which could navigate to more settings fragment. */
|
||||||
|
data class MoreSettingsPreference(
|
||||||
|
@DeviceSettingId override val id: Int,
|
||||||
|
) : DeviceSettingPreferenceModel
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.bluetooth.ui.model
|
||||||
|
|
||||||
|
/** Models a device details fragment type. */
|
||||||
|
sealed interface FragmentTypeModel {
|
||||||
|
/** Device details main page. */
|
||||||
|
data object DeviceDetailsMainFragment : FragmentTypeModel
|
||||||
|
/** Device details more settings page. */
|
||||||
|
data object DeviceDetailsMoreSettingsFragment : FragmentTypeModel
|
||||||
|
}
|
@@ -19,47 +19,52 @@ package com.android.settings.bluetooth.ui.view
|
|||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.util.Log
|
import android.os.Bundle
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
|
import com.android.settings.R
|
||||||
import com.android.settings.SettingsPreferenceFragment
|
import com.android.settings.SettingsPreferenceFragment
|
||||||
import com.android.settings.bluetooth.ui.composable.Icon
|
import com.android.settings.bluetooth.ui.composable.Icon
|
||||||
import com.android.settings.bluetooth.ui.composable.MultiTogglePreferenceGroup
|
import com.android.settings.bluetooth.ui.composable.MultiTogglePreferenceGroup
|
||||||
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
|
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
|
||||||
|
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
|
||||||
|
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
|
||||||
|
import com.android.settings.bluetooth.ui.view.DeviceDetailsMoreSettingsFragment.Companion.KEY_DEVICE_ADDRESS
|
||||||
import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
|
import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
|
||||||
|
import com.android.settings.core.SubSettingLauncher
|
||||||
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
||||||
import com.android.settings.spa.preference.ComposePreference
|
import com.android.settings.spa.preference.ComposePreference
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
|
|
||||||
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
||||||
|
import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
|
||||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||||
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
||||||
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
||||||
import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
|
import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
|
||||||
|
import com.android.settingslib.spa.widget.ui.Footer
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
|
|
||||||
|
|
||||||
|
|
||||||
/** Handles device details fragment layout according to config. */
|
/** Handles device details fragment layout according to config. */
|
||||||
interface DeviceDetailsFragmentFormatter {
|
interface DeviceDetailsFragmentFormatter {
|
||||||
/** Gets keys of visible preferences in built-in preference in xml. */
|
/** Gets keys of visible preferences in built-in preference in xml. */
|
||||||
fun getVisiblePreferenceKeysForMainPage(): List<String>?
|
fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>?
|
||||||
|
|
||||||
/** Updates device details fragment layout. */
|
/** Updates device details fragment layout. */
|
||||||
fun updateLayout()
|
fun updateLayout(fragmentType: FragmentTypeModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@@ -79,23 +84,25 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
ViewModelProvider(
|
ViewModelProvider(
|
||||||
fragment,
|
fragment,
|
||||||
BluetoothDeviceDetailsViewModel.Factory(
|
BluetoothDeviceDetailsViewModel.Factory(
|
||||||
|
fragment.requireActivity().application,
|
||||||
repository,
|
repository,
|
||||||
spatialAudioInteractor,
|
spatialAudioInteractor,
|
||||||
cachedDevice,
|
cachedDevice,
|
||||||
))
|
))
|
||||||
.get(BluetoothDeviceDetailsViewModel::class.java)
|
.get(BluetoothDeviceDetailsViewModel::class.java)
|
||||||
|
|
||||||
override fun getVisiblePreferenceKeysForMainPage(): List<String>? = runBlocking {
|
override fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>? =
|
||||||
|
runBlocking {
|
||||||
viewModel
|
viewModel
|
||||||
.getItems()
|
.getItems(fragmentType)
|
||||||
?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
|
?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
|
||||||
?.mapNotNull { it.preferenceKey }
|
?.mapNotNull { it.preferenceKey }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Updates bluetooth device details fragment layout. */
|
/** Updates bluetooth device details fragment layout. */
|
||||||
override fun updateLayout() = runBlocking {
|
override fun updateLayout(fragmentType: FragmentTypeModel) = runBlocking {
|
||||||
val items = viewModel.getItems() ?: return@runBlocking
|
val items = viewModel.getItems(fragmentType) ?: return@runBlocking
|
||||||
val layout = viewModel.getLayout() ?: return@runBlocking
|
val layout = viewModel.getLayout(fragmentType) ?: return@runBlocking
|
||||||
val prefKeyToSettingId =
|
val prefKeyToSettingId =
|
||||||
items
|
items
|
||||||
.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
|
.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
|
||||||
@@ -124,6 +131,8 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
fragment.preferenceScreen.addPreference(pref)
|
fragment.preferenceScreen.addPreference(pref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO(b/343317785): figure out how to remove the foot preference.
|
||||||
|
fragment.preferenceScreen.addPreference(Preference(context).apply { order = 10000 })
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -132,7 +141,7 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
remember(row) {
|
remember(row) {
|
||||||
layout.rows[row].settingIds.flatMapLatest { settingIds ->
|
layout.rows[row].settingIds.flatMapLatest { settingIds ->
|
||||||
if (settingIds.isEmpty()) {
|
if (settingIds.isEmpty()) {
|
||||||
flowOf(emptyList<DeviceSettingModel>())
|
flowOf(emptyList<DeviceSettingPreferenceModel>())
|
||||||
} else {
|
} else {
|
||||||
combine(
|
combine(
|
||||||
settingIds.map { settingId ->
|
settingIds.map { settingId ->
|
||||||
@@ -150,72 +159,104 @@ class DeviceDetailsFragmentFormatterImpl(
|
|||||||
0 -> {}
|
0 -> {}
|
||||||
1 -> {
|
1 -> {
|
||||||
when (val setting = settings[0]) {
|
when (val setting = settings[0]) {
|
||||||
is DeviceSettingModel.ActionSwitchPreference -> {
|
is DeviceSettingPreferenceModel.PlainPreference -> {
|
||||||
buildActionSwitchPreference(setting)
|
buildPlainPreference(setting)
|
||||||
}
|
}
|
||||||
is DeviceSettingModel.MultiTogglePreference -> {
|
is DeviceSettingPreferenceModel.SwitchPreference -> {
|
||||||
|
buildSwitchPreference(setting)
|
||||||
|
}
|
||||||
|
is DeviceSettingPreferenceModel.MultiTogglePreference -> {
|
||||||
buildMultiTogglePreference(listOf(setting))
|
buildMultiTogglePreference(listOf(setting))
|
||||||
}
|
}
|
||||||
|
is DeviceSettingPreferenceModel.FooterPreference -> {
|
||||||
|
buildFooterPreference(setting)
|
||||||
|
}
|
||||||
|
is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
|
||||||
|
buildMoreSettingsPreference()
|
||||||
|
}
|
||||||
null -> {}
|
null -> {}
|
||||||
else -> {
|
|
||||||
Log.w(TAG, "Unknown preference type ${setting.id}, skip.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
if (!settings.all { it is DeviceSettingModel.MultiTogglePreference }) {
|
if (!settings.all { it is DeviceSettingPreferenceModel.MultiTogglePreference }) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buildMultiTogglePreference(
|
buildMultiTogglePreference(
|
||||||
settings.filterIsInstance<DeviceSettingModel.MultiTogglePreference>())
|
settings.filterIsInstance<DeviceSettingPreferenceModel.MultiTogglePreference>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun buildMultiTogglePreference(prefs: List<DeviceSettingModel.MultiTogglePreference>) {
|
private fun buildMultiTogglePreference(
|
||||||
|
prefs: List<DeviceSettingPreferenceModel.MultiTogglePreference>
|
||||||
|
) {
|
||||||
MultiTogglePreferenceGroup(prefs)
|
MultiTogglePreferenceGroup(prefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun buildActionSwitchPreference(model: DeviceSettingModel.ActionSwitchPreference) {
|
private fun buildSwitchPreference(model: DeviceSettingPreferenceModel.SwitchPreference) {
|
||||||
if (model.switchState != null) {
|
|
||||||
val switchPrefModel =
|
val switchPrefModel =
|
||||||
object : SwitchPreferenceModel {
|
object : SwitchPreferenceModel {
|
||||||
override val title = model.title
|
override val title = model.title
|
||||||
override val summary = { model.summary ?: "" }
|
override val summary = { model.summary ?: "" }
|
||||||
override val checked = { model.switchState?.checked }
|
override val checked = { model.checked }
|
||||||
override val onCheckedChange = { newChecked: Boolean ->
|
override val onCheckedChange = { newChecked: Boolean ->
|
||||||
model.updateState?.invoke(
|
model.onCheckedChange(newChecked)
|
||||||
DeviceSettingStateModel.ActionSwitchPreferenceState(newChecked))
|
|
||||||
Unit
|
|
||||||
}
|
}
|
||||||
override val icon = @Composable { deviceSettingIcon(model) }
|
override val icon = @Composable { deviceSettingIcon(model.icon) }
|
||||||
}
|
}
|
||||||
if (model.intent != null) {
|
if (model.onPrimaryClick != null) {
|
||||||
TwoTargetSwitchPreference(switchPrefModel) { context.startActivity(model.intent) }
|
TwoTargetSwitchPreference(
|
||||||
|
switchPrefModel, primaryOnClick = model.onPrimaryClick::invoke)
|
||||||
} else {
|
} else {
|
||||||
SwitchPreference(switchPrefModel)
|
SwitchPreference(switchPrefModel)
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun buildPlainPreference(model: DeviceSettingPreferenceModel.PlainPreference) {
|
||||||
SpaPreference(
|
SpaPreference(
|
||||||
object : PreferenceModel {
|
object : PreferenceModel {
|
||||||
override val title = model.title
|
override val title = model.title
|
||||||
override val summary = { model.summary ?: "" }
|
override val summary = { model.summary ?: "" }
|
||||||
override val onClick = {
|
override val onClick = {
|
||||||
model.intent?.let { context.startActivity(it) }
|
model.onClick?.invoke()
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
override val icon = @Composable { deviceSettingIcon(model) }
|
override val icon = @Composable { deviceSettingIcon(model.icon) }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun deviceSettingIcon(model: DeviceSettingModel.ActionSwitchPreference) {
|
fun buildMoreSettingsPreference() {
|
||||||
model.icon?.let { icon ->
|
SpaPreference(
|
||||||
Icon(icon, modifier = Modifier.size(SettingsDimension.itemIconSize))
|
object : PreferenceModel {
|
||||||
|
override val title =
|
||||||
|
stringResource(R.string.bluetooth_device_more_settings_preference_title)
|
||||||
|
override val summary = {
|
||||||
|
context.getString(R.string.bluetooth_device_more_settings_preference_summary)
|
||||||
}
|
}
|
||||||
|
override val onClick = {
|
||||||
|
SubSettingLauncher(context)
|
||||||
|
.setDestination(DeviceDetailsMoreSettingsFragment::class.java.name)
|
||||||
|
.setSourceMetricsCategory(fragment.getMetricsCategory())
|
||||||
|
.setArguments(
|
||||||
|
Bundle().apply { putString(KEY_DEVICE_ADDRESS, cachedDevice.address) })
|
||||||
|
.launch()
|
||||||
|
}
|
||||||
|
override val icon = @Composable { deviceSettingIcon(null) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun buildFooterPreference(model: DeviceSettingPreferenceModel.FooterPreference) {
|
||||||
|
Footer(footerText = model.footerText)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun deviceSettingIcon(icon: DeviceSettingIcon?) {
|
||||||
|
icon?.let { Icon(it, modifier = Modifier.size(SettingsDimension.itemIconSize)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
|
private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
|
||||||
|
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.bluetooth.ui.view
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice
|
||||||
|
import android.bluetooth.BluetoothManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.android.settings.bluetooth.BluetoothDetailsProfilesController
|
||||||
|
import com.android.settings.bluetooth.Utils
|
||||||
|
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
|
||||||
|
import com.android.settings.dashboard.DashboardFragment
|
||||||
|
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
||||||
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothManager
|
||||||
|
import com.android.settingslib.core.AbstractPreferenceController
|
||||||
|
import com.android.settingslib.core.lifecycle.LifecycleObserver
|
||||||
|
|
||||||
|
class DeviceDetailsMoreSettingsFragment : DashboardFragment() {
|
||||||
|
private lateinit var formatter: DeviceDetailsFragmentFormatter
|
||||||
|
private lateinit var localBluetoothManager: LocalBluetoothManager
|
||||||
|
private lateinit var cachedDevice: CachedBluetoothDevice
|
||||||
|
|
||||||
|
// TODO(b/343317785): add metrics category
|
||||||
|
override fun getMetricsCategory(): Int = 0
|
||||||
|
|
||||||
|
override fun getPreferenceScreenResId(): Int {
|
||||||
|
return R.xml.bluetooth_device_more_settings_fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addPreferenceController(controller: AbstractPreferenceController) {
|
||||||
|
val keys: List<String>? =
|
||||||
|
formatter.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
|
||||||
|
val lifecycle = settingsLifecycle
|
||||||
|
if (keys == null || keys.contains(controller.preferenceKey)) {
|
||||||
|
super.addPreferenceController(controller)
|
||||||
|
} else if (controller is LifecycleObserver) {
|
||||||
|
lifecycle.removeObserver((controller as LifecycleObserver))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCachedDevice(): CachedBluetoothDevice? {
|
||||||
|
val bluetoothAddress = arguments?.getString(KEY_DEVICE_ADDRESS) ?: return null
|
||||||
|
localBluetoothManager = Utils.getLocalBtManager(context) ?: return null
|
||||||
|
val remoteDevice: BluetoothDevice =
|
||||||
|
localBluetoothManager.bluetoothAdapter.getRemoteDevice(bluetoothAddress) ?: return null
|
||||||
|
return Utils.getLocalBtManager(context).cachedDeviceManager.findDevice(remoteDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
super.onCreatePreferences(savedInstanceState, rootKey)
|
||||||
|
formatter.updateLayout(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createPreferenceControllers(context: Context): List<AbstractPreferenceController> {
|
||||||
|
val bluetoothManager = context.getSystemService(BluetoothManager::class.java)
|
||||||
|
cachedDevice =
|
||||||
|
getCachedDevice()
|
||||||
|
?: run {
|
||||||
|
finish()
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
formatter =
|
||||||
|
featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(
|
||||||
|
requireContext(), this, bluetoothManager.adapter, cachedDevice)
|
||||||
|
return listOf(
|
||||||
|
BluetoothDetailsProfilesController(
|
||||||
|
context, this, localBluetoothManager, cachedDevice, settingsLifecycle))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLogTag(): String = TAG
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG: String = "DeviceMoreSettingsFrg"
|
||||||
|
const val KEY_DEVICE_ADDRESS: String = "device_address"
|
||||||
|
}
|
||||||
|
}
|
@@ -16,17 +16,22 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth.ui.viewmodel
|
package com.android.settings.bluetooth.ui.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
|
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
|
||||||
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
|
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
|
||||||
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow
|
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow
|
||||||
|
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
|
||||||
|
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
||||||
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
|
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
|
||||||
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository
|
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
|
||||||
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
|
||||||
|
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
|
||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
@@ -38,30 +43,81 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
class BluetoothDeviceDetailsViewModel(
|
class BluetoothDeviceDetailsViewModel(
|
||||||
|
private val application: Application,
|
||||||
private val deviceSettingRepository: DeviceSettingRepository,
|
private val deviceSettingRepository: DeviceSettingRepository,
|
||||||
private val spatialAudioInteractor: SpatialAudioInteractor,
|
private val spatialAudioInteractor: SpatialAudioInteractor,
|
||||||
private val cachedDevice: CachedBluetoothDevice,
|
private val cachedDevice: CachedBluetoothDevice,
|
||||||
) : ViewModel() {
|
) : AndroidViewModel(application){
|
||||||
|
|
||||||
private val items =
|
private val items =
|
||||||
viewModelScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
|
viewModelScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
|
||||||
deviceSettingRepository.getDeviceSettingsConfig(cachedDevice)
|
deviceSettingRepository.getDeviceSettingsConfig(cachedDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getItems(): List<DeviceSettingConfigItemModel>? = items.await()?.mainItems
|
suspend fun getItems(fragment: FragmentTypeModel): List<DeviceSettingConfigItemModel>? =
|
||||||
|
when (fragment) {
|
||||||
|
is FragmentTypeModel.DeviceDetailsMainFragment -> items.await()?.mainItems
|
||||||
|
is FragmentTypeModel.DeviceDetailsMoreSettingsFragment ->
|
||||||
|
items.await()?.moreSettingsItems
|
||||||
|
}
|
||||||
|
|
||||||
fun getDeviceSetting(
|
fun getDeviceSetting(
|
||||||
cachedDevice: CachedBluetoothDevice,
|
cachedDevice: CachedBluetoothDevice,
|
||||||
@DeviceSettingId settingId: Int
|
@DeviceSettingId settingId: Int
|
||||||
): Flow<DeviceSettingModel?> {
|
): Flow<DeviceSettingPreferenceModel?> {
|
||||||
|
if (settingId == DeviceSettingId.DEVICE_SETTING_ID_MORE_SETTINGS) {
|
||||||
|
return flowOf(DeviceSettingPreferenceModel.MoreSettingsPreference(settingId))
|
||||||
|
}
|
||||||
return when (settingId) {
|
return when (settingId) {
|
||||||
DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE ->
|
DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE ->
|
||||||
spatialAudioInteractor.getDeviceSetting(cachedDevice)
|
spatialAudioInteractor.getDeviceSetting(cachedDevice)
|
||||||
else -> deviceSettingRepository.getDeviceSetting(cachedDevice, settingId)
|
else -> deviceSettingRepository.getDeviceSetting(cachedDevice, settingId)
|
||||||
|
}.map { it?.toPreferenceModel() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DeviceSettingModel.toPreferenceModel(): DeviceSettingPreferenceModel? {
|
||||||
|
return when (this) {
|
||||||
|
is DeviceSettingModel.ActionSwitchPreference -> {
|
||||||
|
if (switchState != null) {
|
||||||
|
DeviceSettingPreferenceModel.SwitchPreference(
|
||||||
|
id = id,
|
||||||
|
title = title,
|
||||||
|
summary = summary,
|
||||||
|
icon = icon,
|
||||||
|
checked = switchState?.checked ?: false,
|
||||||
|
onCheckedChange = { newState ->
|
||||||
|
updateState?.invoke(
|
||||||
|
DeviceSettingStateModel.ActionSwitchPreferenceState(newState))
|
||||||
|
},
|
||||||
|
onPrimaryClick = { intent?.let { application.startActivity(it) } })
|
||||||
|
} else {
|
||||||
|
DeviceSettingPreferenceModel.PlainPreference(
|
||||||
|
id = id,
|
||||||
|
title = title,
|
||||||
|
summary = summary,
|
||||||
|
icon = icon,
|
||||||
|
onClick = { intent?.let { application.startActivity(it) } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is DeviceSettingModel.FooterPreference ->
|
||||||
|
DeviceSettingPreferenceModel.FooterPreference(id = id, footerText = footerText)
|
||||||
|
is DeviceSettingModel.MultiTogglePreference ->
|
||||||
|
DeviceSettingPreferenceModel.MultiTogglePreference(
|
||||||
|
id = id,
|
||||||
|
title = title,
|
||||||
|
toggles = toggles,
|
||||||
|
isActive = isActive,
|
||||||
|
selectedIndex = state.selectedIndex,
|
||||||
|
isAllowedChangingState = isAllowedChangingState,
|
||||||
|
onSelectedChange = { newState ->
|
||||||
|
updateState(DeviceSettingStateModel.MultiTogglePreferenceState(newState))
|
||||||
|
})
|
||||||
|
is DeviceSettingModel.Unknown -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getLayout(): DeviceSettingLayout? {
|
suspend fun getLayout(fragment: FragmentTypeModel): DeviceSettingLayout? {
|
||||||
val configItems = getItems() ?: return null
|
val configItems = getItems(fragment) ?: return null
|
||||||
val idToDeviceSetting =
|
val idToDeviceSetting =
|
||||||
configItems
|
configItems
|
||||||
.filterIsInstance<DeviceSettingConfigItemModel.AppProvidedItem>()
|
.filterIsInstance<DeviceSettingConfigItemModel.AppProvidedItem>()
|
||||||
@@ -80,7 +136,7 @@ class BluetoothDeviceDetailsViewModel(
|
|||||||
if (!isXmlPreference && setting == null) {
|
if (!isXmlPreference && setting == null) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (setting !is DeviceSettingModel.MultiTogglePreference) {
|
if (setting !is DeviceSettingPreferenceModel.MultiTogglePreference) {
|
||||||
multiToggleSettingIds = null
|
multiToggleSettingIds = null
|
||||||
positionMapping[i] = listOf(configItem.settingId)
|
positionMapping[i] = listOf(configItem.settingId)
|
||||||
continue
|
continue
|
||||||
@@ -103,6 +159,7 @@ class BluetoothDeviceDetailsViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Factory(
|
class Factory(
|
||||||
|
private val application: Application,
|
||||||
private val deviceSettingRepository: DeviceSettingRepository,
|
private val deviceSettingRepository: DeviceSettingRepository,
|
||||||
private val spatialAudioInteractor: SpatialAudioInteractor,
|
private val spatialAudioInteractor: SpatialAudioInteractor,
|
||||||
private val cachedDevice: CachedBluetoothDevice,
|
private val cachedDevice: CachedBluetoothDevice,
|
||||||
@@ -110,7 +167,7 @@ class BluetoothDeviceDetailsViewModel(
|
|||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return BluetoothDeviceDetailsViewModel(
|
return BluetoothDeviceDetailsViewModel(
|
||||||
deviceSettingRepository, spatialAudioInteractor, cachedDevice)
|
application, deviceSettingRepository, spatialAudioInteractor, cachedDevice)
|
||||||
as T
|
as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,6 +43,7 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
import com.android.settings.bluetooth.Utils;
|
import com.android.settings.bluetooth.Utils;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
@@ -128,6 +129,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
+ ", broadcastId = "
|
+ ", broadcastId = "
|
||||||
+ broadcastId);
|
+ broadcastId);
|
||||||
updateSwitch();
|
updateSwitch();
|
||||||
|
AudioSharingUtils.toastMessage(
|
||||||
|
mContext, mContext.getString(R.string.audio_sharing_sharing_label));
|
||||||
mListener.onAudioSharingStateChanged();
|
mListener.onAudioSharingStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +164,9 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
+ ", broadcastId = "
|
+ ", broadcastId = "
|
||||||
+ broadcastId);
|
+ broadcastId);
|
||||||
updateSwitch();
|
updateSwitch();
|
||||||
|
AudioSharingUtils.toastMessage(
|
||||||
|
mContext,
|
||||||
|
mContext.getString(R.string.audio_sharing_sharing_stopped_label));
|
||||||
mListener.onAudioSharingStateChanged();
|
mListener.onAudioSharingStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -278,16 +278,17 @@ public class AdvancedPowerUsageDetail extends DashboardFragment
|
|||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
final int currentOptimizeMode = mBatteryOptimizeUtils.getAppOptimizationMode();
|
final int currentOptimizeMode = mBatteryOptimizeUtils.getAppOptimizationMode();
|
||||||
|
final Context applicationContext = requireContext().getApplicationContext();
|
||||||
mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
|
mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
|
||||||
logMetricCategory(currentOptimizeMode);
|
logMetricCategory(currentOptimizeMode);
|
||||||
mExecutor.execute(
|
mExecutor.execute(
|
||||||
() -> {
|
() -> {
|
||||||
if (currentOptimizeMode != mOptimizationMode) {
|
if (currentOptimizeMode != mOptimizationMode) {
|
||||||
AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(
|
AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(
|
||||||
getContext(), mBatteryOptimizeUtils.getUid());
|
applicationContext, mBatteryOptimizeUtils.getUid());
|
||||||
}
|
}
|
||||||
BatteryOptimizeLogUtils.writeLog(
|
BatteryOptimizeLogUtils.writeLog(
|
||||||
getContext().getApplicationContext(),
|
applicationContext,
|
||||||
Action.LEAVE,
|
Action.LEAVE,
|
||||||
BatteryOptimizeLogUtils.getPackageNameWithUserId(
|
BatteryOptimizeLogUtils.getPackageNameWithUserId(
|
||||||
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
|
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
|
||||||
|
@@ -117,17 +117,17 @@ public class PowerBackgroundUsageDetail extends DashboardFragment
|
|||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
final int currentOptimizeMode = mBatteryOptimizeUtils.getAppOptimizationMode();
|
final int currentOptimizeMode = mBatteryOptimizeUtils.getAppOptimizationMode();
|
||||||
|
final Context applicationContext = requireContext().getApplicationContext();
|
||||||
mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
|
mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
|
||||||
logMetricCategory(currentOptimizeMode);
|
logMetricCategory(currentOptimizeMode);
|
||||||
|
|
||||||
mExecutor.execute(
|
mExecutor.execute(
|
||||||
() -> {
|
() -> {
|
||||||
if (currentOptimizeMode != mOptimizationMode) {
|
if (currentOptimizeMode != mOptimizationMode) {
|
||||||
AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(
|
AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(
|
||||||
getContext(), mBatteryOptimizeUtils.getUid());
|
applicationContext, mBatteryOptimizeUtils.getUid());
|
||||||
}
|
}
|
||||||
BatteryOptimizeLogUtils.writeLog(
|
BatteryOptimizeLogUtils.writeLog(
|
||||||
getContext().getApplicationContext(),
|
applicationContext,
|
||||||
Action.LEAVE,
|
Action.LEAVE,
|
||||||
BatteryOptimizeLogUtils.getPackageNameWithUserId(
|
BatteryOptimizeLogUtils.getPackageNameWithUserId(
|
||||||
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
|
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
|
||||||
|
@@ -56,7 +56,7 @@ public class ImsQueryProvisioningStat implements ImsQuery {
|
|||||||
final ProvisioningManager privisionManager =
|
final ProvisioningManager privisionManager =
|
||||||
ProvisioningManager.createForSubscriptionId(mSubId);
|
ProvisioningManager.createForSubscriptionId(mSubId);
|
||||||
return privisionManager.getProvisioningStatusForCapability(mCapability, mTech);
|
return privisionManager.getProvisioningStatusForCapability(mCapability, mTech);
|
||||||
} catch (IllegalArgumentException exception) {
|
} catch (UnsupportedOperationException exception) {
|
||||||
Log.w(LOG_TAG, "fail to get Provisioning stat. subId=" + mSubId, exception);
|
Log.w(LOG_TAG, "fail to get Provisioning stat. subId=" + mSubId, exception);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@@ -199,7 +199,7 @@ class CarrierConfigRepository(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
fun setStringForTest(subId: Int, key: String, value: String) {
|
fun setStringForTest(subId: Int, key: String, value: String?) {
|
||||||
check(key.endsWith("_string")) { "String key should ends with _string" }
|
check(key.endsWith("_string")) { "String key should ends with _string" }
|
||||||
getPerSubCache(subId)[key] = StringConfigValue(value)
|
getPerSubCache(subId)[key] = StringConfigValue(value)
|
||||||
}
|
}
|
||||||
|
@@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.settings.network.telephony;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.PersistableBundle;
|
|
||||||
import android.telephony.CarrierConfigManager;
|
|
||||||
import android.telephony.SubscriptionManager;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.android.settings.core.BasePreferenceController;
|
|
||||||
import com.android.settings.network.CarrierConfigCache;
|
|
||||||
|
|
||||||
public class CarrierSettingsVersionPreferenceController extends BasePreferenceController {
|
|
||||||
|
|
||||||
private int mSubscriptionId;
|
|
||||||
private CarrierConfigCache mCarrierConfigCache;
|
|
||||||
|
|
||||||
public CarrierSettingsVersionPreferenceController(Context context, String preferenceKey) {
|
|
||||||
super(context, preferenceKey);
|
|
||||||
mCarrierConfigCache = CarrierConfigCache.getInstance(context);
|
|
||||||
mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(int subscriptionId) {
|
|
||||||
mSubscriptionId = subscriptionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharSequence getSummary() {
|
|
||||||
final PersistableBundle config = mCarrierConfigCache.getConfigForSubId(mSubscriptionId);
|
|
||||||
if (config == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return config.getString(CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getAvailabilityStatus() {
|
|
||||||
return TextUtils.isEmpty(getSummary()) ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.network.telephony
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.telephony.CarrierConfigManager
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.android.settings.core.BasePreferenceController
|
||||||
|
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
|
||||||
|
import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
|
||||||
|
|
||||||
|
class CarrierSettingsVersionPreferenceController(context: Context, preferenceKey: String) :
|
||||||
|
BasePreferenceController(context, preferenceKey) {
|
||||||
|
|
||||||
|
private var subId: Int = SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
|
private val searchItem = CarrierSettingsVersionSearchItem(context)
|
||||||
|
|
||||||
|
fun init(subId: Int) {
|
||||||
|
this.subId = subId
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSummary() = searchItem.getSummary(subId)
|
||||||
|
|
||||||
|
override fun getAvailabilityStatus() =
|
||||||
|
if (searchItem.isAvailable(subId)) AVAILABLE else CONDITIONALLY_UNAVAILABLE
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
class CarrierSettingsVersionSearchItem(private val context: Context) :
|
||||||
|
MobileNetworkSettingsSearchItem {
|
||||||
|
private val carrierConfigRepository = CarrierConfigRepository(context)
|
||||||
|
|
||||||
|
fun getSummary(subId: Int): String? =
|
||||||
|
carrierConfigRepository.getString(
|
||||||
|
subId, CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING)
|
||||||
|
|
||||||
|
fun isAvailable(subId: Int): Boolean = !getSummary(subId).isNullOrEmpty()
|
||||||
|
|
||||||
|
override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? {
|
||||||
|
if (!isAvailable(subId)) return null
|
||||||
|
return MobileNetworkSettingsSearchResult(
|
||||||
|
key = "carrier_settings_version_key",
|
||||||
|
title = context.getString(R.string.carrier_settings_version),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -21,6 +21,7 @@ import android.provider.Settings
|
|||||||
import android.telephony.SubscriptionInfo
|
import android.telephony.SubscriptionInfo
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.network.SubscriptionUtil
|
import com.android.settings.network.SubscriptionUtil
|
||||||
|
import com.android.settings.network.telephony.CarrierSettingsVersionPreferenceController.Companion.CarrierSettingsVersionSearchItem
|
||||||
import com.android.settings.network.telephony.DataUsagePreferenceController.Companion.DataUsageSearchItem
|
import com.android.settings.network.telephony.DataUsagePreferenceController.Companion.DataUsageSearchItem
|
||||||
import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
|
import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
|
||||||
import com.android.settings.network.telephony.NrAdvancedCallingPreferenceController.Companion.NrAdvancedCallingSearchItem
|
import com.android.settings.network.telephony.NrAdvancedCallingPreferenceController.Companion.NrAdvancedCallingSearchItem
|
||||||
@@ -115,6 +116,7 @@ class MobileNetworkSettingsSearchIndex(
|
|||||||
|
|
||||||
fun createSearchItems(context: Context): List<MobileNetworkSettingsSearchItem> =
|
fun createSearchItems(context: Context): List<MobileNetworkSettingsSearchItem> =
|
||||||
listOf(
|
listOf(
|
||||||
|
CarrierSettingsVersionSearchItem(context),
|
||||||
DataUsageSearchItem(context),
|
DataUsageSearchItem(context),
|
||||||
MmsMessageSearchItem(context),
|
MmsMessageSearchItem(context),
|
||||||
NrAdvancedCallingSearchItem(context),
|
NrAdvancedCallingSearchItem(context),
|
||||||
|
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.network.telephony.ims
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.telephony.AccessNetworkConstants.TransportType
|
||||||
|
import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability
|
||||||
|
import android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech
|
||||||
|
import com.android.settings.network.telephony.subscriptionsChangedFlow
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A repository for the IMS feature.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if the [subId] is invalid.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
class ImsFeatureRepository(
|
||||||
|
private val context: Context,
|
||||||
|
private val subId: Int,
|
||||||
|
private val provisioningRepository: ProvisioningRepository = ProvisioningRepository(context),
|
||||||
|
private val imsMmTelRepository: ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId)
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* A cold flow that determines the provisioning status for the specified IMS MmTel capability,
|
||||||
|
* and whether or not the requested MmTel capability is supported by the carrier on the
|
||||||
|
* specified network transport.
|
||||||
|
*
|
||||||
|
* @return true if the feature is provisioned and supported, false otherwise.
|
||||||
|
*/
|
||||||
|
fun isReadyFlow(
|
||||||
|
@MmTelCapability capability: Int,
|
||||||
|
@ImsRegistrationTech tech: Int,
|
||||||
|
@TransportType transportType: Int,
|
||||||
|
): Flow<Boolean> =
|
||||||
|
context.subscriptionsChangedFlow().flatMapLatest {
|
||||||
|
combine(
|
||||||
|
provisioningRepository.imsFeatureProvisionedFlow(subId, capability, tech),
|
||||||
|
imsMmTelRepository.isSupportedFlow(capability, transportType),
|
||||||
|
) { imsFeatureProvisioned, isSupported ->
|
||||||
|
imsFeatureProvisioned && isSupported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -36,6 +36,7 @@ import kotlinx.coroutines.flow.callbackFlow
|
|||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.conflate
|
import kotlinx.coroutines.flow.conflate
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@@ -47,6 +48,11 @@ interface ImsMmTelRepository {
|
|||||||
|
|
||||||
fun imsReadyFlow(): Flow<Boolean>
|
fun imsReadyFlow(): Flow<Boolean>
|
||||||
|
|
||||||
|
fun isSupportedFlow(
|
||||||
|
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
||||||
|
@AccessNetworkConstants.TransportType transportType: Int,
|
||||||
|
): Flow<Boolean>
|
||||||
|
|
||||||
suspend fun isSupported(
|
suspend fun isSupported(
|
||||||
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
||||||
@AccessNetworkConstants.TransportType transportType: Int,
|
@AccessNetworkConstants.TransportType transportType: Int,
|
||||||
@@ -55,6 +61,11 @@ interface ImsMmTelRepository {
|
|||||||
suspend fun setCrossSimCallingEnabled(enabled: Boolean)
|
suspend fun setCrossSimCallingEnabled(enabled: Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A repository for the IMS MMTel.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if the [subId] is invalid.
|
||||||
|
*/
|
||||||
class ImsMmTelRepositoryImpl(
|
class ImsMmTelRepositoryImpl(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val subId: Int,
|
private val subId: Int,
|
||||||
@@ -126,8 +137,12 @@ class ImsMmTelRepositoryImpl(
|
|||||||
awaitClose { imsMmTelManager.unregisterImsStateCallback(callback) }
|
awaitClose { imsMmTelManager.unregisterImsStateCallback(callback) }
|
||||||
}.catch { e ->
|
}.catch { e ->
|
||||||
Log.w(TAG, "[$subId] error while imsReadyFlow", e)
|
Log.w(TAG, "[$subId] error while imsReadyFlow", e)
|
||||||
|
emit(false)
|
||||||
}.conflate().flowOn(Dispatchers.Default)
|
}.conflate().flowOn(Dispatchers.Default)
|
||||||
|
|
||||||
|
override fun isSupportedFlow(capability: Int, transportType: Int): Flow<Boolean> =
|
||||||
|
imsReadyFlow().map { imsReady -> imsReady && isSupported(capability, transportType) }
|
||||||
|
|
||||||
override suspend fun isSupported(
|
override suspend fun isSupported(
|
||||||
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
@MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int,
|
||||||
@AccessNetworkConstants.TransportType transportType: Int,
|
@AccessNetworkConstants.TransportType transportType: Int,
|
||||||
|
@@ -20,24 +20,17 @@ import android.content.Context
|
|||||||
import android.telephony.AccessNetworkConstants
|
import android.telephony.AccessNetworkConstants
|
||||||
import android.telephony.CarrierConfigManager
|
import android.telephony.CarrierConfigManager
|
||||||
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
|
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
|
||||||
import android.telephony.SubscriptionManager
|
|
||||||
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
|
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
|
||||||
import android.telephony.ims.feature.MmTelFeature
|
import android.telephony.ims.feature.MmTelFeature
|
||||||
import android.telephony.ims.stub.ImsRegistrationImplBase
|
import android.telephony.ims.stub.ImsRegistrationImplBase
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import com.android.settings.network.telephony.ims.ImsFeatureRepository
|
||||||
import com.android.settings.network.telephony.ims.ImsMmTelRepository
|
import com.android.settings.network.telephony.ims.ImsMmTelRepository
|
||||||
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
|
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
|
||||||
import com.android.settings.network.telephony.ims.ProvisioningRepository
|
|
||||||
import com.android.settings.network.telephony.subscriptionsChangedFlow
|
|
||||||
import com.android.settings.network.telephony.telephonyManager
|
import com.android.settings.network.telephony.telephonyManager
|
||||||
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
interface IWifiCallingRepository {
|
interface IWifiCallingRepository {
|
||||||
@@ -50,11 +43,11 @@ class WifiCallingRepository
|
|||||||
constructor(
|
constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val subId: Int,
|
private val subId: Int,
|
||||||
private val imsMmTelRepository: ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId)
|
private val imsFeatureRepository: ImsFeatureRepository = ImsFeatureRepository(context, subId),
|
||||||
|
private val imsMmTelRepository: ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId),
|
||||||
) : IWifiCallingRepository {
|
) : IWifiCallingRepository {
|
||||||
private val telephonyManager = context.telephonyManager(subId)
|
private val telephonyManager = context.telephonyManager(subId)
|
||||||
|
|
||||||
private val provisioningRepository = ProvisioningRepository(context)
|
|
||||||
private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!!
|
private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!!
|
||||||
|
|
||||||
@WiFiCallingMode
|
@WiFiCallingMode
|
||||||
@@ -76,28 +69,12 @@ constructor(
|
|||||||
wifiCallingReadyFlow().collectLatestWithLifecycle(lifecycleOwner, action = action)
|
wifiCallingReadyFlow().collectLatestWithLifecycle(lifecycleOwner, action = action)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
fun wifiCallingReadyFlow(): Flow<Boolean> =
|
||||||
fun wifiCallingReadyFlow(): Flow<Boolean> {
|
imsFeatureRepository.isReadyFlow(
|
||||||
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
|
|
||||||
return context.subscriptionsChangedFlow().flatMapLatest {
|
|
||||||
combine(
|
|
||||||
provisioningRepository.imsFeatureProvisionedFlow(
|
|
||||||
subId = subId,
|
|
||||||
capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
|
capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
|
||||||
tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
|
tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
|
||||||
),
|
transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
|
||||||
isWifiCallingSupportedFlow(),
|
)
|
||||||
) { imsFeatureProvisioned, isWifiCallingSupported ->
|
|
||||||
imsFeatureProvisioned && isWifiCallingSupported
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isWifiCallingSupportedFlow(): Flow<Boolean> {
|
|
||||||
return imsMmTelRepository.imsReadyFlow().map { imsReady ->
|
|
||||||
imsReady && isWifiCallingSupported()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun isWifiCallingSupported(): Boolean = withContext(Dispatchers.Default) {
|
suspend fun isWifiCallingSupported(): Boolean = withContext(Dispatchers.Default) {
|
||||||
imsMmTelRepository.isSupported(
|
imsMmTelRepository.isSupported(
|
||||||
|
@@ -45,20 +45,21 @@ class InterruptionFilterPreferenceController extends AbstractZenModePreferenceCo
|
|||||||
@Override
|
@Override
|
||||||
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
|
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
|
||||||
preference.setEnabled(zenMode.isEnabled());
|
preference.setEnabled(zenMode.isEnabled());
|
||||||
boolean filteringNotifications = zenMode.getRule().getInterruptionFilter()
|
boolean allowingAll = zenMode.getRule().getInterruptionFilter() == INTERRUPTION_FILTER_ALL;
|
||||||
!= INTERRUPTION_FILTER_ALL;
|
|
||||||
((TwoStatePreference) preference).setChecked(filteringNotifications);
|
((TwoStatePreference) preference).setChecked(allowingAll);
|
||||||
preference.setSummary(filteringNotifications ? "" :
|
preference.setSummary(allowingAll
|
||||||
mContext.getResources().getString(R.string.mode_no_notification_filter));
|
? mContext.getString(R.string.zen_mode_all_notifications_allowed)
|
||||||
|
: "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
|
||||||
final boolean filterNotifications = ((Boolean) newValue);
|
final boolean allowAll = ((Boolean) newValue);
|
||||||
return saveMode(zenMode -> {
|
return saveMode(zenMode -> {
|
||||||
zenMode.getRule().setInterruptionFilter(filterNotifications
|
zenMode.getRule().setInterruptionFilter(allowAll
|
||||||
? INTERRUPTION_FILTER_PRIORITY
|
? INTERRUPTION_FILTER_ALL
|
||||||
: INTERRUPTION_FILTER_ALL);
|
: INTERRUPTION_FILTER_PRIORITY);
|
||||||
return zenMode;
|
return zenMode;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -77,7 +77,7 @@ public class ZenModeFragment extends ZenModeFragmentBase {
|
|||||||
new ZenModeTriggerAddPreferenceController(context, "zen_add_automatic_trigger",
|
new ZenModeTriggerAddPreferenceController(context, "zen_add_automatic_trigger",
|
||||||
this, mBackend));
|
this, mBackend));
|
||||||
prefControllers.add(new InterruptionFilterPreferenceController(
|
prefControllers.add(new InterruptionFilterPreferenceController(
|
||||||
context, "allow_filtering", mBackend));
|
context, "allow_all", mBackend));
|
||||||
prefControllers.add(new ManualDurationPreferenceController(
|
prefControllers.add(new ManualDurationPreferenceController(
|
||||||
context, "mode_manual_duration", this, mBackend));
|
context, "mode_manual_duration", this, mBackend));
|
||||||
return prefControllers;
|
return prefControllers;
|
||||||
@@ -110,9 +110,10 @@ public class ZenModeFragment extends ZenModeFragmentBase {
|
|||||||
if (mode == null || mode.getStatus() != DISABLED_BY_OTHER) {
|
if (mode == null || mode.getStatus() != DISABLED_BY_OTHER) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mContext.startActivity(SetupInterstitialActivity.getIntent(mContext, mode));
|
||||||
// don't come back here from the interstitial
|
// don't come back here from the interstitial
|
||||||
finish();
|
finish();
|
||||||
mContext.startActivity(SetupInterstitialActivity.getIntent(mContext, mode));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -50,6 +50,7 @@ import androidx.fragment.app.FragmentTransaction;
|
|||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.bluetooth.ui.model.FragmentTypeModel;
|
||||||
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
|
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
@@ -117,7 +118,9 @@ public class BluetoothDeviceDetailsFragmentTest {
|
|||||||
FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
|
FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
when(fakeFeatureFactory.mBluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(any(),
|
when(fakeFeatureFactory.mBluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(any(),
|
||||||
any(), any(), eq(mCachedDevice))).thenReturn(mFormatter);
|
any(), any(), eq(mCachedDevice))).thenReturn(mFormatter);
|
||||||
when(mFormatter.getVisiblePreferenceKeysForMainPage()).thenReturn(null);
|
when(mFormatter.getVisiblePreferenceKeys(
|
||||||
|
FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE))
|
||||||
|
.thenReturn(null);
|
||||||
|
|
||||||
mFragment = setupFragment();
|
mFragment = setupFragment();
|
||||||
mFragment.onAttach(mContext);
|
mFragment.onAttach(mContext);
|
||||||
|
@@ -26,6 +26,7 @@ import androidx.preference.PreferenceManager
|
|||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
|
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
|
||||||
|
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
|
||||||
import com.android.settings.dashboard.DashboardFragment
|
import com.android.settings.dashboard.DashboardFragment
|
||||||
import com.android.settings.testutils.FakeFeatureFactory
|
import com.android.settings.testutils.FakeFeatureFactory
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
||||||
@@ -45,7 +46,6 @@ import org.junit.Before
|
|||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentMatchers.any
|
|
||||||
import org.mockito.ArgumentMatchers.eq
|
import org.mockito.ArgumentMatchers.eq
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.any
|
import org.mockito.Mockito.any
|
||||||
@@ -111,10 +111,9 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
DeviceSettingConfigItemModel.BuiltinItem(
|
DeviceSettingConfigItemModel.BuiltinItem(
|
||||||
DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons"),
|
DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, "action_buttons"),
|
||||||
),
|
),
|
||||||
listOf(),
|
listOf()))
|
||||||
"footer"))
|
|
||||||
|
|
||||||
val keys = underTest.getVisiblePreferenceKeysForMainPage()
|
val keys = underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment)
|
||||||
|
|
||||||
assertThat(keys).containsExactly("bluetooth_device_header", "action_buttons")
|
assertThat(keys).containsExactly("bluetooth_device_header", "action_buttons")
|
||||||
}
|
}
|
||||||
@@ -125,7 +124,7 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
`when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null)
|
`when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null)
|
||||||
|
|
||||||
val keys = underTest.getVisiblePreferenceKeysForMainPage()
|
val keys = underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment)
|
||||||
|
|
||||||
assertThat(keys).isNull()
|
assertThat(keys).isNull()
|
||||||
}
|
}
|
||||||
@@ -136,9 +135,9 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
`when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null)
|
`when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null)
|
||||||
|
|
||||||
underTest.updateLayout()
|
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
|
||||||
|
|
||||||
assertThat(getDisplayedPreferences().map { it.key })
|
assertThat(getDisplayedPreferences().mapNotNull { it.key })
|
||||||
.containsExactly("bluetooth_device_header", "action_buttons", "keyboard_settings")
|
.containsExactly("bluetooth_device_header", "action_buttons", "keyboard_settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,12 +156,11 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
|
DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
|
||||||
"keyboard_settings"),
|
"keyboard_settings"),
|
||||||
),
|
),
|
||||||
listOf(),
|
listOf()))
|
||||||
"footer"))
|
|
||||||
|
|
||||||
underTest.updateLayout()
|
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
|
||||||
|
|
||||||
assertThat(getDisplayedPreferences().map { it.key })
|
assertThat(getDisplayedPreferences().mapNotNull { it.key })
|
||||||
.containsExactly("bluetooth_device_header", "keyboard_settings")
|
.containsExactly("bluetooth_device_header", "keyboard_settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,8 +181,7 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
|
DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
|
||||||
"keyboard_settings"),
|
"keyboard_settings"),
|
||||||
),
|
),
|
||||||
listOf(),
|
listOf()))
|
||||||
"footer"))
|
|
||||||
`when`(repository.getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC))
|
`when`(repository.getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC))
|
||||||
.thenReturn(
|
.thenReturn(
|
||||||
flowOf(
|
flowOf(
|
||||||
@@ -209,9 +206,9 @@ class DeviceDetailsFragmentFormatterTest {
|
|||||||
isAllowedChangingState = true,
|
isAllowedChangingState = true,
|
||||||
updateState = {})))
|
updateState = {})))
|
||||||
|
|
||||||
underTest.updateLayout()
|
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
|
||||||
|
|
||||||
assertThat(getDisplayedPreferences().map { it.key })
|
assertThat(getDisplayedPreferences().mapNotNull { it.key })
|
||||||
.containsExactly(
|
.containsExactly(
|
||||||
"bluetooth_device_header",
|
"bluetooth_device_header",
|
||||||
"DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
|
"DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
|
||||||
|
@@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth.ui.viewmodel
|
package com.android.settings.bluetooth.ui.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
|
import com.android.settings.bluetooth.domain.interactor.SpatialAudioInteractor
|
||||||
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
|
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
|
||||||
|
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
|
||||||
|
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
|
||||||
import com.android.settings.testutils.FakeFeatureFactory
|
import com.android.settings.testutils.FakeFeatureFactory
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice
|
||||||
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
|
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
|
||||||
@@ -44,8 +46,6 @@ import org.junit.Before
|
|||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentMatchers.any
|
|
||||||
import org.mockito.ArgumentMatchers.eq
|
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.times
|
import org.mockito.Mockito.times
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
@@ -73,26 +73,23 @@ class BluetoothDeviceDetailsViewModelTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
val application = ApplicationProvider.getApplicationContext<Application>()
|
||||||
featureFactory = FakeFeatureFactory.setupForTest()
|
featureFactory = FakeFeatureFactory.setupForTest()
|
||||||
`when`(
|
|
||||||
featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
|
|
||||||
eq(context), eq(bluetoothAdapter), any()))
|
|
||||||
.thenReturn(repository)
|
|
||||||
|
|
||||||
underTest =
|
underTest =
|
||||||
BluetoothDeviceDetailsViewModel(repository, spatialAudioInteractor, cachedDevice)
|
BluetoothDeviceDetailsViewModel(
|
||||||
|
application, repository, spatialAudioInteractor, cachedDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getItems_returnConfigMainItems() {
|
fun getItems_returnConfigMainMainItems() {
|
||||||
testScope.runTest {
|
testScope.runTest {
|
||||||
`when`(repository.getDeviceSettingsConfig(cachedDevice))
|
`when`(repository.getDeviceSettingsConfig(cachedDevice))
|
||||||
.thenReturn(
|
.thenReturn(
|
||||||
DeviceSettingConfigModel(
|
DeviceSettingConfigModel(
|
||||||
listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf(), "footer"))
|
listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf()))
|
||||||
|
|
||||||
val keys = underTest.getItems()
|
val keys = underTest.getItems(FragmentTypeModel.DeviceDetailsMainFragment)
|
||||||
|
|
||||||
assertThat(keys).containsExactly(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2)
|
assertThat(keys).containsExactly(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2)
|
||||||
}
|
}
|
||||||
@@ -110,19 +107,18 @@ class BluetoothDeviceDetailsViewModelTest {
|
|||||||
BUILTIN_SETTING_ITEM_1,
|
BUILTIN_SETTING_ITEM_1,
|
||||||
buildRemoteSettingItem(remoteSettingId1),
|
buildRemoteSettingItem(remoteSettingId1),
|
||||||
),
|
),
|
||||||
listOf(),
|
listOf()))
|
||||||
"footer"))
|
|
||||||
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
|
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
|
||||||
.thenReturn(flowOf(pref))
|
.thenReturn(flowOf(pref))
|
||||||
|
|
||||||
var deviceSetting: DeviceSettingModel? = null
|
var deviceSettingPreference: DeviceSettingPreferenceModel? = null
|
||||||
underTest
|
underTest
|
||||||
.getDeviceSetting(cachedDevice, remoteSettingId1)
|
.getDeviceSetting(cachedDevice, remoteSettingId1)
|
||||||
.onEach { deviceSetting = it }
|
.onEach { deviceSettingPreference = it }
|
||||||
.launchIn(testScope.backgroundScope)
|
.launchIn(testScope.backgroundScope)
|
||||||
runCurrent()
|
runCurrent()
|
||||||
|
|
||||||
assertThat(deviceSetting).isSameInstanceAs(pref)
|
assertThat(deviceSettingPreference?.id).isEqualTo(pref.id)
|
||||||
verify(repository, times(1)).getDeviceSetting(cachedDevice, remoteSettingId1)
|
verify(repository, times(1)).getDeviceSetting(cachedDevice, remoteSettingId1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,19 +137,18 @@ class BluetoothDeviceDetailsViewModelTest {
|
|||||||
buildRemoteSettingItem(
|
buildRemoteSettingItem(
|
||||||
DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE),
|
DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE),
|
||||||
),
|
),
|
||||||
listOf(),
|
listOf()))
|
||||||
"footer"))
|
|
||||||
`when`(spatialAudioInteractor.getDeviceSetting(cachedDevice)).thenReturn(flowOf(pref))
|
`when`(spatialAudioInteractor.getDeviceSetting(cachedDevice)).thenReturn(flowOf(pref))
|
||||||
|
|
||||||
var deviceSetting: DeviceSettingModel? = null
|
var deviceSettingPreference: DeviceSettingPreferenceModel? = null
|
||||||
underTest
|
underTest
|
||||||
.getDeviceSetting(
|
.getDeviceSetting(
|
||||||
cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE)
|
cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE)
|
||||||
.onEach { deviceSetting = it }
|
.onEach { deviceSettingPreference = it }
|
||||||
.launchIn(testScope.backgroundScope)
|
.launchIn(testScope.backgroundScope)
|
||||||
runCurrent()
|
runCurrent()
|
||||||
|
|
||||||
assertThat(deviceSetting).isSameInstanceAs(pref)
|
assertThat(deviceSettingPreference?.id).isEqualTo(pref.id)
|
||||||
verify(spatialAudioInteractor, times(1)).getDeviceSetting(cachedDevice)
|
verify(spatialAudioInteractor, times(1)).getDeviceSetting(cachedDevice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,9 +159,9 @@ class BluetoothDeviceDetailsViewModelTest {
|
|||||||
`when`(repository.getDeviceSettingsConfig(cachedDevice))
|
`when`(repository.getDeviceSettingsConfig(cachedDevice))
|
||||||
.thenReturn(
|
.thenReturn(
|
||||||
DeviceSettingConfigModel(
|
DeviceSettingConfigModel(
|
||||||
listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf(), "footer"))
|
listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf()))
|
||||||
|
|
||||||
val layout = underTest.getLayout()!!
|
val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
|
||||||
|
|
||||||
assertThat(getLatestLayout(layout))
|
assertThat(getLatestLayout(layout))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
@@ -191,8 +186,7 @@ class BluetoothDeviceDetailsViewModelTest {
|
|||||||
buildRemoteSettingItem(remoteSettingId2),
|
buildRemoteSettingItem(remoteSettingId2),
|
||||||
buildRemoteSettingItem(remoteSettingId3),
|
buildRemoteSettingItem(remoteSettingId3),
|
||||||
),
|
),
|
||||||
listOf(),
|
listOf()))
|
||||||
"footer"))
|
|
||||||
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
|
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
|
||||||
.thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId1)))
|
.thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId1)))
|
||||||
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId2))
|
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId2))
|
||||||
@@ -200,7 +194,7 @@ class BluetoothDeviceDetailsViewModelTest {
|
|||||||
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId3))
|
`when`(repository.getDeviceSetting(cachedDevice, remoteSettingId3))
|
||||||
.thenReturn(flowOf(buildActionSwitchPreference(remoteSettingId3)))
|
.thenReturn(flowOf(buildActionSwitchPreference(remoteSettingId3)))
|
||||||
|
|
||||||
val layout = underTest.getLayout()!!
|
val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
|
||||||
|
|
||||||
assertThat(getLatestLayout(layout))
|
assertThat(getLatestLayout(layout))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
|
@@ -87,7 +87,7 @@ public final class InterruptionFilterPreferenceControllerTest {
|
|||||||
.build();
|
.build();
|
||||||
mController.updateZenMode(preference, zenMode);
|
mController.updateZenMode(preference, zenMode);
|
||||||
|
|
||||||
verify(preference).setChecked(false);
|
verify(preference).setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -99,7 +99,7 @@ public final class InterruptionFilterPreferenceControllerTest {
|
|||||||
|
|
||||||
mController.updateZenMode(preference, zenMode);
|
mController.updateZenMode(preference, zenMode);
|
||||||
|
|
||||||
mController.onPreferenceChange(preference, true);
|
mController.onPreferenceChange(preference, false);
|
||||||
|
|
||||||
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
|
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
|
||||||
verify(mBackend).updateMode(captor.capture());
|
verify(mBackend).updateMode(captor.capture());
|
||||||
@@ -118,7 +118,7 @@ public final class InterruptionFilterPreferenceControllerTest {
|
|||||||
.build();
|
.build();
|
||||||
mController.updateZenMode(preference, zenMode);
|
mController.updateZenMode(preference, zenMode);
|
||||||
|
|
||||||
verify(preference).setChecked(true);
|
verify(preference).setChecked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -131,7 +131,7 @@ public final class InterruptionFilterPreferenceControllerTest {
|
|||||||
|
|
||||||
mController.updateZenMode(preference, zenMode);
|
mController.updateZenMode(preference, zenMode);
|
||||||
|
|
||||||
mController.onPreferenceChange(preference, false);
|
mController.onPreferenceChange(preference, true);
|
||||||
|
|
||||||
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
|
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
|
||||||
verify(mBackend).updateMode(captor.capture());
|
verify(mBackend).updateMode(captor.capture());
|
||||||
|
@@ -18,11 +18,9 @@ package com.android.settings.notification.modes;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.app.AutomaticZenRule;
|
|
||||||
import android.app.Flags;
|
import android.app.Flags;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
|
||||||
import android.platform.test.annotations.EnableFlags;
|
import android.platform.test.annotations.EnableFlags;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -31,7 +29,6 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
import com.android.settingslib.notification.modes.TestModeBuilder;
|
import com.android.settingslib.notification.modes.TestModeBuilder;
|
||||||
import com.android.settingslib.notification.modes.ZenMode;
|
|
||||||
import com.android.settingslib.notification.modes.ZenModesBackend;
|
import com.android.settingslib.notification.modes.ZenModesBackend;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -73,10 +70,8 @@ public class ManualDurationPreferenceControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testIsAvailable_onlyForManualDnd() {
|
public void testIsAvailable_onlyForManualDnd() {
|
||||||
assertThat(mPrefController.isAvailable(TestModeBuilder.EXAMPLE)).isFalse();
|
assertThat(mPrefController.isAvailable(TestModeBuilder.EXAMPLE)).isFalse();
|
||||||
|
assertThat(mPrefController.isAvailable(TestModeBuilder.MANUAL_DND_ACTIVE)).isTrue();
|
||||||
ZenMode manualDnd = ZenMode.manualDndMode(
|
assertThat(mPrefController.isAvailable(TestModeBuilder.MANUAL_DND_INACTIVE)).isTrue();
|
||||||
new AutomaticZenRule.Builder("id", Uri.EMPTY).build(), false);
|
|
||||||
assertThat(mPrefController.isAvailable(manualDnd)).isTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -23,11 +23,9 @@ import static org.mockito.Mockito.mock;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.AutomaticZenRule;
|
|
||||||
import android.app.Flags;
|
import android.app.Flags;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
|
||||||
import android.platform.test.annotations.EnableFlags;
|
import android.platform.test.annotations.EnableFlags;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -192,8 +190,7 @@ public final class ZenModeButtonPreferenceControllerTest {
|
|||||||
Button button = new Button(mContext);
|
Button button = new Button(mContext);
|
||||||
LayoutPreference pref = mock(LayoutPreference.class);
|
LayoutPreference pref = mock(LayoutPreference.class);
|
||||||
when(pref.findViewById(anyInt())).thenReturn(button);
|
when(pref.findViewById(anyInt())).thenReturn(button);
|
||||||
ZenMode zenMode = ZenMode.manualDndMode(
|
ZenMode zenMode = TestModeBuilder.MANUAL_DND_INACTIVE;
|
||||||
new AutomaticZenRule.Builder("manual", Uri.EMPTY).build(), false);
|
|
||||||
|
|
||||||
mController.updateZenMode(pref, zenMode);
|
mController.updateZenMode(pref, zenMode);
|
||||||
button.callOnClick();
|
button.callOnClick();
|
||||||
@@ -207,8 +204,7 @@ public final class ZenModeButtonPreferenceControllerTest {
|
|||||||
Button button = new Button(mContext);
|
Button button = new Button(mContext);
|
||||||
LayoutPreference pref = mock(LayoutPreference.class);
|
LayoutPreference pref = mock(LayoutPreference.class);
|
||||||
when(pref.findViewById(anyInt())).thenReturn(button);
|
when(pref.findViewById(anyInt())).thenReturn(button);
|
||||||
ZenMode zenMode = ZenMode.manualDndMode(
|
ZenMode zenMode = TestModeBuilder.MANUAL_DND_INACTIVE;
|
||||||
new AutomaticZenRule.Builder("manual", Uri.EMPTY).build(), false);
|
|
||||||
|
|
||||||
mController.updateZenMode(pref, zenMode);
|
mController.updateZenMode(pref, zenMode);
|
||||||
button.callOnClick();
|
button.callOnClick();
|
||||||
|
@@ -19,7 +19,6 @@ package com.android.settings.notification.modes;
|
|||||||
import static android.app.AutomaticZenRule.TYPE_OTHER;
|
import static android.app.AutomaticZenRule.TYPE_OTHER;
|
||||||
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
|
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
|
||||||
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
|
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
|
||||||
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
|
|
||||||
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
|
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
|
||||||
|
|
||||||
import static com.android.settings.notification.modes.CharSequenceTruth.assertThat;
|
import static com.android.settings.notification.modes.CharSequenceTruth.assertThat;
|
||||||
@@ -28,7 +27,6 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.app.AutomaticZenRule;
|
|
||||||
import android.app.Flags;
|
import android.app.Flags;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -125,12 +123,7 @@ public class ZenModeTriggerAddPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isAvailable_manualDND_false() {
|
public void isAvailable_manualDND_false() {
|
||||||
ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb",
|
mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
|
||||||
Uri.parse("manual"))
|
|
||||||
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
|
|
||||||
.build(), /* isActive= */ false);
|
|
||||||
|
|
||||||
mController.setZenMode(manualMode);
|
|
||||||
assertThat(mController.isAvailable()).isFalse();
|
assertThat(mController.isAvailable()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,15 +18,12 @@ package com.android.settings.notification.modes;
|
|||||||
|
|
||||||
import static android.app.AutomaticZenRule.TYPE_OTHER;
|
import static android.app.AutomaticZenRule.TYPE_OTHER;
|
||||||
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
|
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
|
||||||
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
|
|
||||||
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
|
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.app.AutomaticZenRule;
|
|
||||||
import android.app.Flags;
|
import android.app.Flags;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
|
||||||
import android.platform.test.annotations.EnableFlags;
|
import android.platform.test.annotations.EnableFlags;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
import android.service.notification.SystemZenRules;
|
import android.service.notification.SystemZenRules;
|
||||||
@@ -116,12 +113,7 @@ public class ZenModeTriggerCategoryPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isAvailable_manualDND_false() {
|
public void isAvailable_manualDND_false() {
|
||||||
ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb",
|
mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
|
||||||
Uri.parse("manual"))
|
|
||||||
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
|
|
||||||
.build(), /* isActive= */ false);
|
|
||||||
|
|
||||||
mController.setZenMode(manualMode);
|
|
||||||
assertThat(mController.isAvailable()).isFalse();
|
assertThat(mController.isAvailable()).isFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,6 @@ package com.android.settings.notification.modes;
|
|||||||
import static android.app.AutomaticZenRule.TYPE_OTHER;
|
import static android.app.AutomaticZenRule.TYPE_OTHER;
|
||||||
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
|
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
|
||||||
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
|
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
|
||||||
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
|
|
||||||
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
|
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
|
||||||
|
|
||||||
import static com.android.settings.notification.modes.CharSequenceTruth.assertThat;
|
import static com.android.settings.notification.modes.CharSequenceTruth.assertThat;
|
||||||
@@ -35,13 +34,11 @@ import static org.mockito.Mockito.when;
|
|||||||
import static org.robolectric.Shadows.shadowOf;
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.AutomaticZenRule;
|
|
||||||
import android.app.Flags;
|
import android.app.Flags;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.platform.test.annotations.EnableFlags;
|
import android.platform.test.annotations.EnableFlags;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
@@ -149,12 +146,7 @@ public class ZenModeTriggerUpdatePreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isAvailable_manualDND_false() {
|
public void isAvailable_manualDND_false() {
|
||||||
ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb",
|
mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
|
||||||
Uri.parse("manual"))
|
|
||||||
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
|
|
||||||
.build(), /* isActive= */ false);
|
|
||||||
|
|
||||||
mController.setZenMode(manualMode);
|
|
||||||
assertThat(mController.isAvailable()).isFalse();
|
assertThat(mController.isAvailable()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,8 @@ package com.android.settings.notification.modes;
|
|||||||
|
|
||||||
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
|
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
|
||||||
|
|
||||||
|
import static com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_INACTIVE;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -71,13 +73,6 @@ public class ZenModesListPreferenceControllerTest {
|
|||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private static final ZenMode TEST_MANUAL_MODE = ZenMode.manualDndMode(
|
|
||||||
new AutomaticZenRule.Builder("Do Not Disturb", Uri.EMPTY)
|
|
||||||
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
|
|
||||||
.setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
|
|
||||||
.build(),
|
|
||||||
false);
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(
|
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(
|
||||||
SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
|
SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
|
||||||
@@ -152,7 +147,7 @@ public class ZenModesListPreferenceControllerTest {
|
|||||||
@DisableFlags(Flags.FLAG_MODES_UI)
|
@DisableFlags(Flags.FLAG_MODES_UI)
|
||||||
public void testModesUiOff_notAvailableAndNoSearchData() {
|
public void testModesUiOff_notAvailableAndNoSearchData() {
|
||||||
// There exist modes
|
// There exist modes
|
||||||
when(mBackend.getModes()).thenReturn(List.of(TEST_MANUAL_MODE, TEST_MODE));
|
when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE, TEST_MODE));
|
||||||
|
|
||||||
assertThat(mPrefController.isAvailable()).isFalse();
|
assertThat(mPrefController.isAvailable()).isFalse();
|
||||||
List<SearchIndexableRaw> data = new ArrayList<>();
|
List<SearchIndexableRaw> data = new ArrayList<>();
|
||||||
@@ -187,20 +182,20 @@ public class ZenModesListPreferenceControllerTest {
|
|||||||
|
|
||||||
// Changing mode data so there's a different one mode doesn't keep any previous data
|
// Changing mode data so there's a different one mode doesn't keep any previous data
|
||||||
// (and setting that state up in the caller)
|
// (and setting that state up in the caller)
|
||||||
when(mBackend.getModes()).thenReturn(List.of(TEST_MANUAL_MODE));
|
when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE));
|
||||||
List<SearchIndexableRaw> newData = new ArrayList<>();
|
List<SearchIndexableRaw> newData = new ArrayList<>();
|
||||||
mPrefController.updateDynamicRawDataToIndex(newData);
|
mPrefController.updateDynamicRawDataToIndex(newData);
|
||||||
assertThat(newData).hasSize(1);
|
assertThat(newData).hasSize(1);
|
||||||
|
|
||||||
SearchIndexableRaw newItem = newData.get(0);
|
SearchIndexableRaw newItem = newData.get(0);
|
||||||
assertThat(newItem.key).isEqualTo(TEST_MANUAL_MODE.getId());
|
assertThat(newItem.key).isEqualTo(MANUAL_DND_INACTIVE.getId());
|
||||||
assertThat(newItem.title).isEqualTo("Do Not Disturb"); // set above
|
assertThat(newItem.title).isEqualTo("Do Not Disturb"); // set above
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@EnableFlags(Flags.FLAG_MODES_UI)
|
@EnableFlags(Flags.FLAG_MODES_UI)
|
||||||
public void testUpdateDynamicRawDataToIndex_multipleModes() {
|
public void testUpdateDynamicRawDataToIndex_multipleModes() {
|
||||||
when(mBackend.getModes()).thenReturn(List.of(TEST_MANUAL_MODE, TEST_MODE));
|
when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE, TEST_MODE));
|
||||||
|
|
||||||
List<SearchIndexableRaw> data = new ArrayList<>();
|
List<SearchIndexableRaw> data = new ArrayList<>();
|
||||||
mPrefController.updateDynamicRawDataToIndex(data);
|
mPrefController.updateDynamicRawDataToIndex(data);
|
||||||
@@ -208,7 +203,7 @@ public class ZenModesListPreferenceControllerTest {
|
|||||||
|
|
||||||
// Should keep the order presented by getModes()
|
// Should keep the order presented by getModes()
|
||||||
SearchIndexableRaw item0 = data.get(0);
|
SearchIndexableRaw item0 = data.get(0);
|
||||||
assertThat(item0.key).isEqualTo(TEST_MANUAL_MODE.getId());
|
assertThat(item0.key).isEqualTo(MANUAL_DND_INACTIVE.getId());
|
||||||
assertThat(item0.title).isEqualTo("Do Not Disturb"); // set above
|
assertThat(item0.title).isEqualTo("Do Not Disturb"); // set above
|
||||||
|
|
||||||
SearchIndexableRaw item1 = data.get(1);
|
SearchIndexableRaw item1 = data.get(1);
|
||||||
|
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.network.telephony
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.telephony.CarrierConfigManager
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class CarrierSettingsVersionPreferenceControllerTest {
|
||||||
|
|
||||||
|
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
|
|
||||||
|
private val controller =
|
||||||
|
CarrierSettingsVersionPreferenceController(context, TEST_KEY).apply { init(SUB_ID) }
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
CarrierConfigRepository.resetForTest()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_nullConfig_noCrash() {
|
||||||
|
controller.getSummary()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_nullVersionString_returnNull() {
|
||||||
|
CarrierConfigRepository.setStringForTest(
|
||||||
|
SUB_ID, CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING, null)
|
||||||
|
|
||||||
|
val summary = controller.getSummary()
|
||||||
|
|
||||||
|
assertThat(summary).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getSummary_hasVersionString_returnCorrectSummary() {
|
||||||
|
CarrierConfigRepository.setStringForTest(
|
||||||
|
SUB_ID, CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING, "test_version_123")
|
||||||
|
|
||||||
|
val summary = controller.getSummary()
|
||||||
|
|
||||||
|
assertThat(summary).isEqualTo("test_version_123")
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val TEST_KEY = "test_key"
|
||||||
|
const val SUB_ID = 10
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.network.telephony.ims
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.telephony.AccessNetworkConstants
|
||||||
|
import android.telephony.ims.feature.MmTelFeature
|
||||||
|
import android.telephony.ims.stub.ImsRegistrationImplBase
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.stub
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ImsFeatureRepositoryTest {
|
||||||
|
|
||||||
|
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
|
|
||||||
|
private val mockProvisioningRepository = mock<ProvisioningRepository>()
|
||||||
|
private val mockImsMmTelRepository = mock<ImsMmTelRepository>()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isReadyFlow_notProvisioned_returnFalse() = runBlocking {
|
||||||
|
mockProvisioningRepository.stub {
|
||||||
|
onBlocking { imsFeatureProvisionedFlow(SUB_ID, CAPABILITY, TECH) } doReturn
|
||||||
|
flowOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val repository =
|
||||||
|
ImsFeatureRepository(
|
||||||
|
context = context,
|
||||||
|
subId = SUB_ID,
|
||||||
|
provisioningRepository = mockProvisioningRepository,
|
||||||
|
)
|
||||||
|
|
||||||
|
val isReady = repository.isReadyFlow(CAPABILITY, TECH, TRANSPORT_TYPE).first()
|
||||||
|
|
||||||
|
assertThat(isReady).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isReadyFlow_notSupported_returnFalse() = runBlocking {
|
||||||
|
mockImsMmTelRepository.stub {
|
||||||
|
onBlocking { isSupportedFlow(CAPABILITY, TRANSPORT_TYPE) } doReturn flowOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val repository =
|
||||||
|
ImsFeatureRepository(
|
||||||
|
context = context,
|
||||||
|
subId = SUB_ID,
|
||||||
|
imsMmTelRepository = mockImsMmTelRepository,
|
||||||
|
)
|
||||||
|
|
||||||
|
val isReady = repository.isReadyFlow(CAPABILITY, TECH, TRANSPORT_TYPE).first()
|
||||||
|
|
||||||
|
assertThat(isReady).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isReadyFlow_provisionedAndSupported_returnFalse() = runBlocking {
|
||||||
|
mockProvisioningRepository.stub {
|
||||||
|
onBlocking { imsFeatureProvisionedFlow(SUB_ID, CAPABILITY, TECH) } doReturn flowOf(true)
|
||||||
|
}
|
||||||
|
mockImsMmTelRepository.stub {
|
||||||
|
onBlocking { isSupportedFlow(CAPABILITY, TRANSPORT_TYPE) } doReturn flowOf(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
val repository =
|
||||||
|
ImsFeatureRepository(
|
||||||
|
context = context,
|
||||||
|
subId = SUB_ID,
|
||||||
|
provisioningRepository = mockProvisioningRepository,
|
||||||
|
imsMmTelRepository = mockImsMmTelRepository,
|
||||||
|
)
|
||||||
|
|
||||||
|
val isReady = repository.isReadyFlow(CAPABILITY, TECH, TRANSPORT_TYPE).first()
|
||||||
|
|
||||||
|
assertThat(isReady).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val SUB_ID = 10
|
||||||
|
const val CAPABILITY = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE
|
||||||
|
const val TECH = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN
|
||||||
|
const val TRANSPORT_TYPE = AccessNetworkConstants.TRANSPORT_TYPE_WLAN
|
||||||
|
}
|
||||||
|
}
|
@@ -55,7 +55,8 @@ class WifiCallingRepositoryTest {
|
|||||||
on { getWiFiCallingMode(any()) } doReturn ImsMmTelManager.WIFI_MODE_UNKNOWN
|
on { getWiFiCallingMode(any()) } doReturn ImsMmTelManager.WIFI_MODE_UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
private val repository = WifiCallingRepository(context, SUB_ID, mockImsMmTelRepository)
|
private val repository =
|
||||||
|
WifiCallingRepository(context, SUB_ID, imsMmTelRepository = mockImsMmTelRepository)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getWiFiCallingMode_roamingAndNotUseWfcHomeModeForRoaming_returnRoamingSetting() {
|
fun getWiFiCallingMode_roamingAndNotUseWfcHomeModeForRoaming_returnRoamingSetting() {
|
||||||
|
@@ -1,79 +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.network.telephony;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.PersistableBundle;
|
|
||||||
import android.telephony.CarrierConfigManager;
|
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
|
|
||||||
import com.android.settings.network.CarrierConfigCache;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class CarrierSettingsVersionPreferenceControllerTest {
|
|
||||||
@Mock
|
|
||||||
private CarrierConfigCache mCarrierConfigCache;
|
|
||||||
|
|
||||||
private CarrierSettingsVersionPreferenceController mController;
|
|
||||||
private int mSubscriptionId = 1234;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
Context context = spy(ApplicationProvider.getApplicationContext());
|
|
||||||
CarrierConfigCache.setTestInstance(context, mCarrierConfigCache);
|
|
||||||
mController = new CarrierSettingsVersionPreferenceController(context, "mock_key");
|
|
||||||
mController.init(mSubscriptionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getSummary_nullConfig_noCrash() {
|
|
||||||
doReturn(null).when(mCarrierConfigCache).getConfigForSubId(mSubscriptionId);
|
|
||||||
|
|
||||||
assertThat(mController.getSummary()).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getSummary_nullVersionString_noCrash() {
|
|
||||||
doReturn(new PersistableBundle()).when(mCarrierConfigCache)
|
|
||||||
.getConfigForSubId(mSubscriptionId);
|
|
||||||
assertThat(mController.getSummary()).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getSummary_hasVersionString_correctSummary() {
|
|
||||||
final PersistableBundle bundle = new PersistableBundle();
|
|
||||||
bundle.putString(CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING,
|
|
||||||
"test_version_123");
|
|
||||||
doReturn(bundle).when(mCarrierConfigCache).getConfigForSubId(mSubscriptionId);
|
|
||||||
|
|
||||||
assertThat(mController.getSummary()).isEqualTo("test_version_123");
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user