Snap for 11591048 from 59a329cae5 to 24Q3-release
Change-Id: I70f629898beaf25d659539a215056bc7245fcef1
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
package: "com.android.settings.development"
|
package: "com.android.settings.development"
|
||||||
container: "system"
|
container: "system"
|
||||||
|
|
||||||
|
flag {
|
||||||
|
name: "a2dp_offload_codec_extensibility_settings"
|
||||||
|
namespace: "bluetooth"
|
||||||
|
description: "Feature flag for Bluetooth Audio Codec extensibility in Settings"
|
||||||
|
bug: "323319530"
|
||||||
|
}
|
||||||
|
|
||||||
flag {
|
flag {
|
||||||
name: "deprecate_list_activity"
|
name: "deprecate_list_activity"
|
||||||
namespace: "android_settings"
|
namespace: "android_settings"
|
||||||
|
|||||||
@@ -178,6 +178,9 @@
|
|||||||
<!-- Description for text in accessibility hearing aids footer. [CHAR LIMIT=NONE] -->
|
<!-- Description for text in accessibility hearing aids footer. [CHAR LIMIT=NONE] -->
|
||||||
<string name="bluetooth_audio_routing_footer_summary">By default, audio output is determined by individual apps</string>
|
<string name="bluetooth_audio_routing_footer_summary">By default, audio output is determined by individual apps</string>
|
||||||
|
|
||||||
|
<!-- Bluetooth audio codec related settings. Title of the default audio codec selection. [CHAR LIMIT=60] -->
|
||||||
|
<string name="bluetooth_audio_codec_default_selection">Use System Selection (Default)</string>
|
||||||
|
|
||||||
<!--Bluetooth settings screen, summary text for Bluetooth device with no name -->
|
<!--Bluetooth settings screen, summary text for Bluetooth device with no name -->
|
||||||
<string name="bluetooth_device">Unnamed Bluetooth device</string>
|
<string name="bluetooth_device">Unnamed Bluetooth device</string>
|
||||||
<!--Bluetooth settings screen, text that appears in heading bar when scanning for devices -->
|
<!--Bluetooth settings screen, text that appears in heading bar when scanning for devices -->
|
||||||
@@ -1551,20 +1554,12 @@
|
|||||||
<string name="unlock_disable_frp_warning_content_pattern_face_fingerprint">"A pattern protects your phone if it\u2019s lost or stolen.<xliff:g id="empty_line">\n\n</xliff:g>This deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps."</string>
|
<string name="unlock_disable_frp_warning_content_pattern_face_fingerprint">"A pattern protects your phone if it\u2019s lost or stolen.<xliff:g id="empty_line">\n\n</xliff:g>This deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps."</string>
|
||||||
<!-- Content of the dialog shown when the user removes the device lock PIN [CHAR LIMIT=NONE] -->
|
<!-- Content of the dialog shown when the user removes the device lock PIN [CHAR LIMIT=NONE] -->
|
||||||
<string name="unlock_disable_frp_warning_content_pin">"A PIN protects your phone if it\u2019s lost or stolen"</string>
|
<string name="unlock_disable_frp_warning_content_pin">"A PIN protects your phone if it\u2019s lost or stolen"</string>
|
||||||
<!-- Content of the dialog shown when the user removes the device lock PIN and there are apps with auth-bound keys that will be affected [CHAR LIMIT=NONE] -->
|
|
||||||
<string name="unlock_disable_frp_warning_content_pin_authbound_keys">"You will lose saved data like your PIN.<xliff:g id="empty_line">\n\n</xliff:g>Cards set up for tap to pay will be removed.<xliff:g id="empty_line">\n\n</xliff:g>Wallets and other apps that require device unlock may not work properly."</string>
|
|
||||||
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has fingerprints enrolled [CHAR LIMIT=NONE] -->
|
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has fingerprints enrolled [CHAR LIMIT=NONE] -->
|
||||||
<string name="unlock_disable_frp_warning_content_pin_fingerprint">"A PIN protects your phone if it\u2019s lost or stolen.<xliff:g id="empty_line">\n\n</xliff:g>This also deletes the fingerprint model stored on your device. You won\u2019t be able to use your fingerprint for authentication in apps."</string>
|
<string name="unlock_disable_frp_warning_content_pin_fingerprint">"A PIN protects your phone if it\u2019s lost or stolen.<xliff:g id="empty_line">\n\n</xliff:g>This also deletes the fingerprint model stored on your device. You won\u2019t be able to use your fingerprint for authentication in apps."</string>
|
||||||
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has fingerprints enrolled and there are apps with auth-bound keys that will be affected [CHAR LIMIT=NONE] -->
|
|
||||||
<string name="unlock_disable_frp_warning_content_pin_fingerprint_authbound_keys">"You will lose saved data like your PIN and fingerprint model.<xliff:g id="empty_line">\n\n</xliff:g>Cards set up for tap to pay will be removed.<xliff:g id="empty_line">\n\n</xliff:g>Wallets and other apps that require device unlock may not work properly."</string>
|
|
||||||
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has face enrolled [CHAR LIMIT=NONE] -->
|
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has face enrolled [CHAR LIMIT=NONE] -->
|
||||||
<string name="unlock_disable_frp_warning_content_pin_face">"A PIN protects your phone if it\u2019s lost or stolen.<xliff:g id="empty_line">\n\n</xliff:g>Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face for authentication in apps."</string>
|
<string name="unlock_disable_frp_warning_content_pin_face">"A PIN protects your phone if it\u2019s lost or stolen.<xliff:g id="empty_line">\n\n</xliff:g>Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face for authentication in apps."</string>
|
||||||
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has face enrolled and there are apps with auth-bound keys that will be affected [CHAR LIMIT=NONE] -->
|
|
||||||
<string name="unlock_disable_frp_warning_content_pin_face_authbound_keys">"You will lose saved data like your PIN and face model.<xliff:g id="empty_line">\n\n</xliff:g>Cards set up for tap to pay will be removed.<xliff:g id="empty_line">\n\n</xliff:g>Wallets and other apps that require device unlock may not work properly."</string>
|
|
||||||
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has face authentication and fingerprint enrolled [CHAR LIMIT=NONE] -->
|
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has face authentication and fingerprint enrolled [CHAR LIMIT=NONE] -->
|
||||||
<string name="unlock_disable_frp_warning_content_pin_face_fingerprint">"A PIN protects your phone if it\u2019s lost or stolen.<xliff:g id="empty_line">\n\n</xliff:g>This deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps."</string>
|
<string name="unlock_disable_frp_warning_content_pin_face_fingerprint">"A PIN protects your phone if it\u2019s lost or stolen.<xliff:g id="empty_line">\n\n</xliff:g>This deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps."</string>
|
||||||
<!-- Content of the dialog shown when the user removes the device lock PIN and the user has face authentication and fingerprint enrolled and there are apps with auth-bound keys that will be affected [CHAR LIMIT=NONE] -->
|
|
||||||
<string name="unlock_disable_frp_warning_content_pin_face_fingerprint_authbound_keys">"You will lose saved data like your PIN, face and fingerprint models.<xliff:g id="empty_line">\n\n</xliff:g>Cards set up for tap to pay will be removed.<xliff:g id="empty_line">\n\n</xliff:g>Wallets and other apps that require device unlock may not work properly."</string>
|
|
||||||
<!-- Content of the dialog shown when the user removes the device lock password [CHAR LIMIT=NONE] -->
|
<!-- Content of the dialog shown when the user removes the device lock password [CHAR LIMIT=NONE] -->
|
||||||
<string name="unlock_disable_frp_warning_content_password">"A password protects your phone if it\u2019s lost or stolen"</string>
|
<string name="unlock_disable_frp_warning_content_password">"A password protects your phone if it\u2019s lost or stolen"</string>
|
||||||
<!-- Content of the dialog shown when the user removes the device lock password and the user has fingerprints enrolled [CHAR LIMIT=NONE] -->
|
<!-- Content of the dialog shown when the user removes the device lock password and the user has fingerprints enrolled [CHAR LIMIT=NONE] -->
|
||||||
@@ -1581,6 +1576,15 @@
|
|||||||
<string name="unlock_disable_frp_warning_content_unknown_face">"Device protection features will not work without your screen lock.<xliff:g id="empty_line">\n\n</xliff:g>Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face for authentication in apps."</string>
|
<string name="unlock_disable_frp_warning_content_unknown_face">"Device protection features will not work without your screen lock.<xliff:g id="empty_line">\n\n</xliff:g>Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face for authentication in apps."</string>
|
||||||
<!-- Content of the dialog shown when the user removes the device lock of unknown type and the user has face authentication and fingerprint enrolled [CHAR LIMIT=NONE] -->
|
<!-- Content of the dialog shown when the user removes the device lock of unknown type and the user has face authentication and fingerprint enrolled [CHAR LIMIT=NONE] -->
|
||||||
<string name="unlock_disable_frp_warning_content_unknown_face_fingerprint">"Device protection features will not work without your screen lock.<xliff:g id="empty_line">\n\n</xliff:g>This deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps."</string>
|
<string name="unlock_disable_frp_warning_content_unknown_face_fingerprint">"Device protection features will not work without your screen lock.<xliff:g id="empty_line">\n\n</xliff:g>This deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps."</string>
|
||||||
|
<!-- Content of the dialog shown when the user removes any device screenlock and there are apps with auth-bound keys that will be affected [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="unlock_disable_frp_warning_content_authbound_keys">"Your screen lock will be removed.<xliff:g id="empty_line">\n\n</xliff:g>Tap to pay won\u2019t be available.<xliff:g id="empty_line">\n\n</xliff:g>Wallet, payment, and other apps that require authentication may not work properly."</string>
|
||||||
|
<!-- Content of the dialog shown when the user removes any device screen lock and the user has fingerprints enrolled and there are apps with auth-bound keys that will be affected [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="unlock_disable_frp_warning_content_fingerprint_authbound_keys">"Your screen lock and Fingerprint Unlock will be removed.<xliff:g id="empty_line">\n\n</xliff:g>Tap to pay won\u2019t be available.<xliff:g id="empty_line">\n\n</xliff:g>Wallet, payment, and other apps that require authentication may not work properly."</string>
|
||||||
|
<!-- Content of the dialog shown when the user removes any device screen lock and the user has face enrolled and there are apps with auth-bound keys that will be affected [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="unlock_disable_frp_warning_content_face_authbound_keys">"Your screen lock and Face Unlock will be removed.<xliff:g id="empty_line">\n\n</xliff:g>Tap to pay won\u2019t be available.<xliff:g id="empty_line">\n\n</xliff:g>Wallet, payment, and other apps that require authentication may not work properly."</string>
|
||||||
|
<!-- Content of the dialog shown when the user removes any device screen lock and the user has face authentication and fingerprint enrolled and there are apps with auth-bound keys that will be affected [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="unlock_disable_frp_warning_content_face_fingerprint_authbound_keys">"Your screen lock and Face & Fingerprint Unlock will be removed.<xliff:g id="empty_line">\n\n</xliff:g>Tap to pay won\u2019t be available.<xliff:g id="empty_line">\n\n</xliff:g>Wallet, payment, and other apps that require authentication may not work properly."</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Affirmative action of the dialog shown when the user removes the device lock [CHAR LIMIT=25] -->
|
<!-- Affirmative action of the dialog shown when the user removes the device lock [CHAR LIMIT=25] -->
|
||||||
<string name="unlock_disable_frp_warning_ok">Delete</string>
|
<string name="unlock_disable_frp_warning_ok">Delete</string>
|
||||||
@@ -2320,6 +2324,8 @@
|
|||||||
<string name="wifi_details_title">Network details</string>
|
<string name="wifi_details_title">Network details</string>
|
||||||
<!-- Wifi details preference title to display router IP subnet mask -->
|
<!-- Wifi details preference title to display router IP subnet mask -->
|
||||||
<string name="wifi_details_subnet_mask">Subnet mask</string>
|
<string name="wifi_details_subnet_mask">Subnet mask</string>
|
||||||
|
<!-- Server name title-->
|
||||||
|
<string name="server_name_title">Server name</string>
|
||||||
<!-- Wifi details preference title to display wifi type info [CHAR LIMIT=50]-->
|
<!-- Wifi details preference title to display wifi type info [CHAR LIMIT=50]-->
|
||||||
<string name="wifi_type_title">Type</string>
|
<string name="wifi_type_title">Type</string>
|
||||||
<!-- Wifi details preference title to display router DNS info -->
|
<!-- Wifi details preference title to display router DNS info -->
|
||||||
@@ -3198,9 +3204,18 @@
|
|||||||
<!-- Body of dialog confirming that user wants to forget an internal storage device [CHAR LIMIT=NONE]-->
|
<!-- Body of dialog confirming that user wants to forget an internal storage device [CHAR LIMIT=NONE]-->
|
||||||
<string name="storage_internal_forget_confirm">All the apps, photos, and data stored on this <xliff:g id="name" example="SD card">^1</xliff:g> will be lost forever.</string>
|
<string name="storage_internal_forget_confirm">All the apps, photos, and data stored on this <xliff:g id="name" example="SD card">^1</xliff:g> will be lost forever.</string>
|
||||||
|
|
||||||
<!-- Body of dialog informing user about the storage used by the Android System [CHAR LIMIT=NONE]-->
|
<!-- Old body of dialog informing user about the storage used by the Android System [CHAR LIMIT=NONE]-->
|
||||||
<string name="storage_detail_dialog_system">System includes files used to run Android version <xliff:g id="version" example="8.0">%s</xliff:g></string>
|
<string name="storage_detail_dialog_system">System includes files used to run Android version <xliff:g id="version" example="8.0">%s</xliff:g></string>
|
||||||
|
|
||||||
|
<!-- New body of dialog informing user about the storage used by the Android System [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="storage_os_detail_dialog_system">This includes your operating system and the files that are needed to keep your phone running smoothly. To protect their integrity, these files can\u2019t be accessed.</string>
|
||||||
|
|
||||||
|
<!-- Body of dialog informing user about the storage used by the Android temporary system files [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="storage_other_files_detail_dialog_system">This includes cache and other temporary files that are needed by your operating system. You may notice changes to the amount of storage used over time.</string>
|
||||||
|
|
||||||
|
<!-- Label for categories splitter in Settings > Storage [CHAR LIMIT=none] -->
|
||||||
|
<string name="storage_system_label">System</string>
|
||||||
|
|
||||||
<!-- Message to notify guest users as to why they can't set up the storage device [CHAR LIMIT=50]-->
|
<!-- Message to notify guest users as to why they can't set up the storage device [CHAR LIMIT=50]-->
|
||||||
<string name="storage_wizard_guest">Guest mode users cannot format SD cards</string>
|
<string name="storage_wizard_guest">Guest mode users cannot format SD cards</string>
|
||||||
|
|
||||||
@@ -10855,9 +10870,15 @@
|
|||||||
<!-- Preference label for the Documents & other storage section. [CHAR LIMIT=50] -->
|
<!-- Preference label for the Documents & other storage section. [CHAR LIMIT=50] -->
|
||||||
<string name="storage_documents_and_other">Documents & other</string>
|
<string name="storage_documents_and_other">Documents & other</string>
|
||||||
|
|
||||||
<!-- Preference label for the System storage section. [CHAR LIMIT=50] -->
|
<!-- Old Preference label for the System storage section. [CHAR LIMIT=50] -->
|
||||||
<string name="storage_system">System</string>
|
<string name="storage_system">System</string>
|
||||||
|
|
||||||
|
<!-- New Preference label for the System storage section. [CHAR LIMIT=50] -->
|
||||||
|
<string name="storage_os_name">Android <xliff:g id="version" example="8">%s</xliff:g></string>
|
||||||
|
|
||||||
|
<!-- Preference label for the System storage section. [CHAR LIMIT=50] -->
|
||||||
|
<string name="storage_temporary_files">Temporary system files</string>
|
||||||
|
|
||||||
<!-- Preference label for the Trash storage section. [CHAR LIMIT=50] -->
|
<!-- Preference label for the Trash storage section. [CHAR LIMIT=50] -->
|
||||||
<string name="storage_trash">Trash</string>
|
<string name="storage_trash">Trash</string>
|
||||||
|
|
||||||
|
|||||||
@@ -430,6 +430,11 @@
|
|||||||
android:positiveButtonText=""
|
android:positiveButtonText=""
|
||||||
android:negativeButtonText="@string/dlg_ok"/>
|
android:negativeButtonText="@string/dlg_ok"/>
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="bluetooth_audio_codec_settings_list"
|
||||||
|
android:title="@string/bluetooth_select_a2dp_codec_type"
|
||||||
|
android:dialogTitle="@string/bluetooth_select_a2dp_codec_type_dialog_title"/>
|
||||||
|
|
||||||
<com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreference
|
<com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreference
|
||||||
android:key="bluetooth_sample_rate_settings"
|
android:key="bluetooth_sample_rate_settings"
|
||||||
android:title="@string/bluetooth_select_a2dp_codec_sample_rate"
|
android:title="@string/bluetooth_select_a2dp_codec_sample_rate"
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ public final class PreferredShortcuts {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the user preferred shortcut types for the given {@code componentName} from
|
* Retrieves the user preferred shortcut types for the given {@code componentName} from
|
||||||
* SharedPreferences.
|
* SharedPreferences. If the user doesn't have a preferred shortcut,
|
||||||
|
* {@link ShortcutConstants.UserShortcutType.SOFTWARE} is returned.
|
||||||
*
|
*
|
||||||
* @param context {@link Context} to access the {@link SharedPreferences}
|
* @param context {@link Context} to access the {@link SharedPreferences}
|
||||||
* @param componentName Name of the service or activity, should be the format of {@link
|
* @param componentName Name of the service or activity, should be the format of {@link
|
||||||
@@ -52,7 +53,26 @@ public final class PreferredShortcuts {
|
|||||||
@ShortcutConstants.UserShortcutType
|
@ShortcutConstants.UserShortcutType
|
||||||
public static int retrieveUserShortcutType(
|
public static int retrieveUserShortcutType(
|
||||||
@NonNull Context context, @NonNull String componentName) {
|
@NonNull Context context, @NonNull String componentName) {
|
||||||
final int defaultTypes = getDefaultPreferredShortcutTypesForTarget(componentName);
|
return retrieveUserShortcutType(
|
||||||
|
context, componentName, ShortcutConstants.UserShortcutType.SOFTWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the user preferred shortcut types for the given {@code componentName} from
|
||||||
|
* SharedPreferences.
|
||||||
|
*
|
||||||
|
* @param context {@link Context} to access the {@link SharedPreferences}
|
||||||
|
* @param componentName Name of the service or activity, should be the format of {@link
|
||||||
|
* ComponentName#flattenToString()}.
|
||||||
|
* @param defaultTypes The default shortcut types to use if the user doesn't have a
|
||||||
|
* preferred shortcut.
|
||||||
|
* @return {@link ShortcutConstants.UserShortcutType}
|
||||||
|
*/
|
||||||
|
@ShortcutConstants.UserShortcutType
|
||||||
|
public static int retrieveUserShortcutType(
|
||||||
|
@NonNull Context context,
|
||||||
|
@NonNull String componentName,
|
||||||
|
@ShortcutConstants.UserShortcutType int defaultTypes) {
|
||||||
|
|
||||||
// Create a mutable set to modify
|
// Create a mutable set to modify
|
||||||
final Set<String> info = new HashSet<>(getFromSharedPreferences(context));
|
final Set<String> info = new HashSet<>(getFromSharedPreferences(context));
|
||||||
@@ -150,14 +170,5 @@ public final class PreferredShortcuts {
|
|||||||
getSharedPreferences(context).edit().clear().apply();
|
getSharedPreferences(context).edit().clear().apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the default shortcut types for the given accessibility feature.
|
|
||||||
*/
|
|
||||||
@ShortcutConstants.UserShortcutType
|
|
||||||
private static int getDefaultPreferredShortcutTypesForTarget(@NonNull String componentName) {
|
|
||||||
// TODO (b/322712028): return different default shortcut types for the given component
|
|
||||||
return ShortcutConstants.UserShortcutType.SOFTWARE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PreferredShortcuts() {}
|
private PreferredShortcuts() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import android.widget.CompoundButton;
|
|||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.internal.accessibility.common.ShortcutConstants;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||||
import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
|
import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
|
||||||
@@ -330,7 +331,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
|||||||
@Override
|
@Override
|
||||||
public void onToggleClicked(ShortcutPreference preference) {
|
public void onToggleClicked(ShortcutPreference preference) {
|
||||||
final int shortcutTypes = retrieveUserShortcutType(getPrefContext(),
|
final int shortcutTypes = retrieveUserShortcutType(getPrefContext(),
|
||||||
mComponentName.flattenToString());
|
mComponentName.flattenToString(), getDefaultShortcutTypes());
|
||||||
if (preference.isChecked()) {
|
if (preference.isChecked()) {
|
||||||
final boolean isWarningRequired;
|
final boolean isWarningRequired;
|
||||||
if (android.view.accessibility.Flags.cleanupAccessibilityWarningDialog()) {
|
if (android.view.accessibility.Flags.cleanupAccessibilityWarningDialog()) {
|
||||||
@@ -476,6 +477,16 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
|||||||
return TAG;
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getDefaultShortcutTypes() {
|
||||||
|
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||||
|
return getTileComponentName() == null ? super.getDefaultShortcutTypes()
|
||||||
|
: ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getDefaultShortcutTypes();
|
||||||
|
}
|
||||||
|
|
||||||
private void onAllowButtonFromEnableToggleClicked() {
|
private void onAllowButtonFromEnableToggleClicked() {
|
||||||
handleConfirmServiceEnabled(/* confirmed= */ true);
|
handleConfirmServiceEnabled(/* confirmed= */ true);
|
||||||
if (serviceSupportsAccessibilityButton()) {
|
if (serviceSupportsAccessibilityButton()) {
|
||||||
@@ -507,7 +518,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends
|
|||||||
mShortcutPreference.setChecked(true);
|
mShortcutPreference.setChecked(true);
|
||||||
|
|
||||||
final int shortcutTypes = retrieveUserShortcutType(getPrefContext(),
|
final int shortcutTypes = retrieveUserShortcutType(getPrefContext(),
|
||||||
mComponentName.flattenToString());
|
mComponentName.flattenToString(), getDefaultShortcutTypes());
|
||||||
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName);
|
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName);
|
||||||
|
|
||||||
mIsDialogShown.set(false);
|
mIsDialogShown.set(false);
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import androidx.preference.Preference;
|
|||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.internal.accessibility.common.ShortcutConstants;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType;
|
import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType;
|
||||||
@@ -661,7 +662,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
int value = restoreOnConfigChangedValue();
|
int value = restoreOnConfigChangedValue();
|
||||||
if (value == NOT_SET) {
|
if (value == NOT_SET) {
|
||||||
final int lastNonEmptyUserShortcutType = PreferredShortcuts.retrieveUserShortcutType(
|
final int lastNonEmptyUserShortcutType = PreferredShortcuts.retrieveUserShortcutType(
|
||||||
getPrefContext(), mComponentName.flattenToString());
|
getPrefContext(), mComponentName.flattenToString(), getDefaultShortcutTypes());
|
||||||
value = mShortcutPreference.isChecked() ? lastNonEmptyUserShortcutType
|
value = mShortcutPreference.isChecked() ? lastNonEmptyUserShortcutType
|
||||||
: UserShortcutType.EMPTY;
|
: UserShortcutType.EMPTY;
|
||||||
}
|
}
|
||||||
@@ -710,8 +711,8 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
return context.getText(R.string.accessibility_shortcut_state_off);
|
return context.getText(R.string.accessibility_shortcut_state_off);
|
||||||
}
|
}
|
||||||
|
|
||||||
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
|
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(
|
||||||
mComponentName.flattenToString());
|
context, mComponentName.flattenToString(), getDefaultShortcutTypes());
|
||||||
|
|
||||||
final List<CharSequence> list = new ArrayList<>();
|
final List<CharSequence> list = new ArrayList<>();
|
||||||
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
if (android.view.accessibility.Flags.a11yQsShortcut()) {
|
||||||
@@ -811,7 +812,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
|
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
|
||||||
mComponentName.flattenToString());
|
mComponentName.flattenToString(), getDefaultShortcutTypes());
|
||||||
mShortcutPreference.setChecked(
|
mShortcutPreference.setChecked(
|
||||||
AccessibilityUtil.hasValuesInSettings(getPrefContext(), shortcutTypes,
|
AccessibilityUtil.hasValuesInSettings(getPrefContext(), shortcutTypes,
|
||||||
mComponentName));
|
mComponentName));
|
||||||
@@ -829,7 +830,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
|
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
|
||||||
mComponentName.flattenToString());
|
mComponentName.flattenToString(), getDefaultShortcutTypes());
|
||||||
if (preference.isChecked()) {
|
if (preference.isChecked()) {
|
||||||
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,
|
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,
|
||||||
mComponentName);
|
mComponentName);
|
||||||
@@ -977,4 +978,13 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
|
|||||||
boolean isAnySetupWizard() {
|
boolean isAnySetupWizard() {
|
||||||
return WizardManagerHelper.isAnySetupWizard(getIntent());
|
return WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default preferred shortcut types when the user doesn't have a preferred shortcut
|
||||||
|
* types
|
||||||
|
*/
|
||||||
|
@ShortcutConstants.UserShortcutType
|
||||||
|
protected int getDefaultShortcutTypes() {
|
||||||
|
return ShortcutConstants.UserShortcutType.SOFTWARE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import com.android.settings.Settings;
|
|||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.SubSettings;
|
import com.android.settings.SubSettings;
|
||||||
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
|
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
|
||||||
|
import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal;
|
||||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
|
||||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
|
||||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal;
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal;
|
||||||
@@ -259,6 +260,7 @@ public class ActivityEmbeddingRulesController {
|
|||||||
addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class);
|
addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class);
|
||||||
addActivityFilter(activityFilters, FingerprintEnrollIntroductionInternal.class);
|
addActivityFilter(activityFilters, FingerprintEnrollIntroductionInternal.class);
|
||||||
addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
|
addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
|
||||||
|
addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class);
|
||||||
addActivityFilter(activityFilters, FaceEnrollIntroduction.class);
|
addActivityFilter(activityFilters, FaceEnrollIntroduction.class);
|
||||||
addActivityFilter(activityFilters, RemoteAuthActivity.class);
|
addActivityFilter(activityFilters, RemoteAuthActivity.class);
|
||||||
addActivityFilter(activityFilters, RemoteAuthActivityInternal.class);
|
addActivityFilter(activityFilters, RemoteAuthActivityInternal.class);
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ import com.android.settings.biometrics.BiometricsEnrollEnrolling;
|
|||||||
import com.android.settings.biometrics.BiometricsSplitScreenDialog;
|
import com.android.settings.biometrics.BiometricsSplitScreenDialog;
|
||||||
import com.android.settings.biometrics.fingerprint.feature.SfpsEnrollmentFeature;
|
import com.android.settings.biometrics.fingerprint.feature.SfpsEnrollmentFeature;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
import com.android.settings.flags.Flags;
|
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.display.DisplayDensityUtils;
|
import com.android.settingslib.display.DisplayDensityUtils;
|
||||||
|
|
||||||
@@ -252,12 +251,6 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
|||||||
|
|
||||||
setContentView(layout);
|
setContentView(layout);
|
||||||
setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
|
setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
|
||||||
|
|
||||||
if (Flags.udfpsEnrollCalibration()) {
|
|
||||||
mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider()
|
|
||||||
.getUdfpsEnrollCalibrator(getApplicationContext(), savedInstanceState,
|
|
||||||
getIntent());
|
|
||||||
}
|
|
||||||
} else if (mCanAssumeSfps) {
|
} else if (mCanAssumeSfps) {
|
||||||
mSfpsEnrollmentFeature = FeatureFactory.getFeatureFactory()
|
mSfpsEnrollmentFeature = FeatureFactory.getFeatureFactory()
|
||||||
.getFingerprintFeatureProvider().getSfpsEnrollmentFeature();
|
.getFingerprintFeatureProvider().getSfpsEnrollmentFeature();
|
||||||
@@ -342,6 +335,15 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
|||||||
|
|
||||||
final Configuration config = getApplicationContext().getResources().getConfiguration();
|
final Configuration config = getApplicationContext().getResources().getConfiguration();
|
||||||
maybeHideSfpsText(config);
|
maybeHideSfpsText(config);
|
||||||
|
|
||||||
|
if (!mIsSetupWizard) {
|
||||||
|
mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider()
|
||||||
|
.getUdfpsEnrollCalibrator(getApplicationContext(), null, getIntent());
|
||||||
|
if (mCalibrator != null) {
|
||||||
|
mCalibrator.onWaitingPage(getLifecycle(),
|
||||||
|
getSupportFragmentManager(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setHelpAnimation() {
|
private void setHelpAnimation() {
|
||||||
@@ -371,11 +373,6 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
|||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putBoolean(KEY_STATE_CANCELED, mIsCanceled);
|
outState.putBoolean(KEY_STATE_CANCELED, mIsCanceled);
|
||||||
outState.putInt(KEY_STATE_PREVIOUS_ROTATION, mPreviousRotation);
|
outState.putInt(KEY_STATE_PREVIOUS_ROTATION, mPreviousRotation);
|
||||||
if (Flags.udfpsEnrollCalibration()) {
|
|
||||||
if (mCalibrator != null) {
|
|
||||||
mCalibrator.onSaveInstanceState(outState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreSavedState(Bundle savedInstanceState) {
|
private void restoreSavedState(Bundle savedInstanceState) {
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
|||||||
.getUdfpsEnrollCalibrator(getApplicationContext(), savedInstanceState,
|
.getUdfpsEnrollCalibrator(getApplicationContext(), savedInstanceState,
|
||||||
getIntent());
|
getIntent());
|
||||||
if (mCalibrator != null) {
|
if (mCalibrator != null) {
|
||||||
mCalibrator.onFindSensorPage(
|
mCalibrator.onWaitingPage(
|
||||||
getLifecycle(),
|
getLifecycle(),
|
||||||
getSupportFragmentManager(),
|
getSupportFragmentManager(),
|
||||||
this::enableUdfpsLottieAndNextButton
|
this::enableUdfpsLottieAndNextButton
|
||||||
@@ -296,7 +296,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
|
|||||||
getIntent().getIntExtra(BiometricUtils.EXTRA_ENROLL_REASON, -1));
|
getIntent().getIntExtra(BiometricUtils.EXTRA_ENROLL_REASON, -1));
|
||||||
if (Flags.udfpsEnrollCalibration()) {
|
if (Flags.udfpsEnrollCalibration()) {
|
||||||
if (mCalibrator != null) {
|
if (mCalibrator != null) {
|
||||||
ret.putExtras(mCalibrator.getExtrasForNextIntent(true));
|
ret.putExtras(mCalibrator.getExtrasForNextIntent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
|||||||
}
|
}
|
||||||
if (Flags.udfpsEnrollCalibration()) {
|
if (Flags.udfpsEnrollCalibration()) {
|
||||||
if (mCalibrator != null) {
|
if (mCalibrator != null) {
|
||||||
intent.putExtras(mCalibrator.getExtrasForNextIntent(false));
|
intent.putExtras(mCalibrator.getExtrasForNextIntent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
intent.putExtra(BiometricUtils.EXTRA_ENROLL_REASON,
|
intent.putExtra(BiometricUtils.EXTRA_ENROLL_REASON,
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ import com.android.settingslib.transition.SettingsTransitionHelper;
|
|||||||
import com.android.settingslib.widget.FooterPreference;
|
import com.android.settingslib.widget.FooterPreference;
|
||||||
import com.android.settingslib.widget.TwoTargetPreference;
|
import com.android.settingslib.widget.TwoTargetPreference;
|
||||||
|
|
||||||
|
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||||
import com.google.android.setupdesign.util.DeviceHelper;
|
import com.google.android.setupdesign.util.DeviceHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -111,6 +112,9 @@ public class FingerprintSettings extends SubSettings {
|
|||||||
private static final int RESULT_SKIP = BiometricEnrollBase.RESULT_SKIP;
|
private static final int RESULT_SKIP = BiometricEnrollBase.RESULT_SKIP;
|
||||||
private static final int RESULT_TIMEOUT = BiometricEnrollBase.RESULT_TIMEOUT;
|
private static final int RESULT_TIMEOUT = BiometricEnrollBase.RESULT_TIMEOUT;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private UdfpsEnrollCalibrator mCalibrator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Intent getIntent() {
|
public Intent getIntent() {
|
||||||
Intent modIntent = new Intent(super.getIntent());
|
Intent modIntent = new Intent(super.getIntent());
|
||||||
@@ -131,6 +135,13 @@ public class FingerprintSettings extends SubSettings {
|
|||||||
setTitle(msg);
|
setTitle(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider()
|
||||||
|
.getUdfpsEnrollCalibrator(getApplicationContext(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context
|
* @param context
|
||||||
* @return true if the Fingerprint hardware is detected.
|
* @return true if the Fingerprint hardware is detected.
|
||||||
@@ -800,6 +811,11 @@ public class FingerprintSettings extends SubSettings {
|
|||||||
}
|
}
|
||||||
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
|
||||||
|
if (((FingerprintSettings) getActivity()).mCalibrator != null) {
|
||||||
|
intent.putExtras(
|
||||||
|
(((FingerprintSettings) getActivity()).mCalibrator)
|
||||||
|
.getExtrasForNextIntent());
|
||||||
|
}
|
||||||
startActivityForResult(intent, ADD_FINGERPRINT_REQUEST);
|
startActivityForResult(intent, ADD_FINGERPRINT_REQUEST);
|
||||||
} else if (pref instanceof FingerprintPreference) {
|
} else if (pref instanceof FingerprintPreference) {
|
||||||
FingerprintPreference fpref = (FingerprintPreference) pref;
|
FingerprintPreference fpref = (FingerprintPreference) pref;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class SetupFingerprintEnrollFindSensor extends FingerprintEnrollFindSenso
|
|||||||
SetupWizardUtils.copySetupExtras(getIntent(), intent);
|
SetupWizardUtils.copySetupExtras(getIntent(), intent);
|
||||||
if (Flags.udfpsEnrollCalibration()) {
|
if (Flags.udfpsEnrollCalibration()) {
|
||||||
if (mCalibrator != null) {
|
if (mCalibrator != null) {
|
||||||
intent.putExtras(mCalibrator.getExtrasForNextIntent(true));
|
intent.putExtras(mCalibrator.getExtrasForNextIntent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return intent;
|
return intent;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntrodu
|
|||||||
SetupWizardUtils.copySetupExtras(getIntent(), intent);
|
SetupWizardUtils.copySetupExtras(getIntent(), intent);
|
||||||
if (Flags.udfpsEnrollCalibration()) {
|
if (Flags.udfpsEnrollCalibration()) {
|
||||||
if (mCalibrator != null) {
|
if (mCalibrator != null) {
|
||||||
intent.putExtras(mCalibrator.getExtrasForNextIntent(false));
|
intent.putExtras(mCalibrator.getExtrasForNextIntent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return intent;
|
return intent;
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ import androidx.lifecycle.Lifecycle
|
|||||||
|
|
||||||
interface UdfpsEnrollCalibrator {
|
interface UdfpsEnrollCalibrator {
|
||||||
|
|
||||||
fun getExtrasForNextIntent(isEnrolling: Boolean): Bundle
|
fun getExtrasForNextIntent(): Bundle
|
||||||
|
|
||||||
fun onSaveInstanceState(outState: Bundle)
|
fun onSaveInstanceState(outState: Bundle)
|
||||||
|
|
||||||
fun onFindSensorPage(
|
fun onWaitingPage(
|
||||||
lifecycle: Lifecycle,
|
lifecycle: Lifecycle,
|
||||||
fragmentManager: FragmentManager,
|
fragmentManager: FragmentManager,
|
||||||
enableEnrollingRunnable: Runnable
|
enableEnrollingRunnable: Runnable?
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -16,15 +16,19 @@
|
|||||||
|
|
||||||
package com.android.settings.development;
|
package com.android.settings.development;
|
||||||
|
|
||||||
|
import android.annotation.FlaggedApi;
|
||||||
import android.bluetooth.BluetoothCodecConfig;
|
import android.bluetooth.BluetoothCodecConfig;
|
||||||
|
import android.bluetooth.BluetoothCodecType;
|
||||||
|
|
||||||
/**
|
import androidx.annotation.NonNull;
|
||||||
* Utility class for storing current Bluetooth A2DP profile values
|
import androidx.annotation.Nullable;
|
||||||
*/
|
|
||||||
|
/** Utility class for storing current Bluetooth A2DP profile values */
|
||||||
public class BluetoothA2dpConfigStore {
|
public class BluetoothA2dpConfigStore {
|
||||||
|
|
||||||
// init default values
|
// init default values
|
||||||
private int mCodecType = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
|
private int mCodecTypeNative = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
|
||||||
|
@Nullable private BluetoothCodecType mCodecType = null;
|
||||||
private int mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
|
private int mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
|
||||||
private int mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
|
private int mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
|
||||||
private int mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
|
private int mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
|
||||||
@@ -35,6 +39,10 @@ public class BluetoothA2dpConfigStore {
|
|||||||
private long mCodecSpecific4Value;
|
private long mCodecSpecific4Value;
|
||||||
|
|
||||||
public void setCodecType(int codecType) {
|
public void setCodecType(int codecType) {
|
||||||
|
mCodecTypeNative = codecType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCodecType(@Nullable BluetoothCodecType codecType) {
|
||||||
mCodecType = codecType;
|
mCodecType = codecType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,9 +78,26 @@ public class BluetoothA2dpConfigStore {
|
|||||||
mCodecSpecific4Value = codecSpecific4Value;
|
mCodecSpecific4Value = codecSpecific4Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Create codec config utilizing {@link BluetoothCodecConfig.SourceCodecType} */
|
||||||
public BluetoothCodecConfig createCodecConfig() {
|
public BluetoothCodecConfig createCodecConfig() {
|
||||||
return new BluetoothCodecConfig.Builder()
|
return new BluetoothCodecConfig.Builder()
|
||||||
.setCodecType(mCodecType)
|
.setCodecType(mCodecTypeNative)
|
||||||
|
.setCodecPriority(mCodecPriority)
|
||||||
|
.setSampleRate(mSampleRate)
|
||||||
|
.setBitsPerSample(mBitsPerSample)
|
||||||
|
.setChannelMode(mChannelMode)
|
||||||
|
.setCodecSpecific1(mCodecSpecific1Value)
|
||||||
|
.setCodecSpecific2(mCodecSpecific2Value)
|
||||||
|
.setCodecSpecific3(mCodecSpecific3Value)
|
||||||
|
.setCodecSpecific4(mCodecSpecific4Value)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create codec config utilizing {@link BluetoothCodecType} */
|
||||||
|
@FlaggedApi(Flags.FLAG_A2DP_OFFLOAD_CODEC_EXTENSIBILITY_SETTINGS)
|
||||||
|
public @NonNull BluetoothCodecConfig createCodecConfigFromCodecType() {
|
||||||
|
return new BluetoothCodecConfig.Builder()
|
||||||
|
.setExtendedCodecType(mCodecType)
|
||||||
.setCodecPriority(mCodecPriority)
|
.setCodecPriority(mCodecPriority)
|
||||||
.setSampleRate(mSampleRate)
|
.setSampleRate(mSampleRate)
|
||||||
.setBitsPerSample(mBitsPerSample)
|
.setBitsPerSample(mBitsPerSample)
|
||||||
|
|||||||
@@ -62,10 +62,12 @@ import com.android.settings.development.autofill.AutofillCategoryController;
|
|||||||
import com.android.settings.development.autofill.AutofillLoggingLevelPreferenceController;
|
import com.android.settings.development.autofill.AutofillLoggingLevelPreferenceController;
|
||||||
import com.android.settings.development.autofill.AutofillResetOptionsPreferenceController;
|
import com.android.settings.development.autofill.AutofillResetOptionsPreferenceController;
|
||||||
import com.android.settings.development.bluetooth.AbstractBluetoothDialogPreferenceController;
|
import com.android.settings.development.bluetooth.AbstractBluetoothDialogPreferenceController;
|
||||||
|
import com.android.settings.development.bluetooth.AbstractBluetoothListPreferenceController;
|
||||||
import com.android.settings.development.bluetooth.AbstractBluetoothPreferenceController;
|
import com.android.settings.development.bluetooth.AbstractBluetoothPreferenceController;
|
||||||
import com.android.settings.development.bluetooth.BluetoothBitPerSampleDialogPreferenceController;
|
import com.android.settings.development.bluetooth.BluetoothBitPerSampleDialogPreferenceController;
|
||||||
import com.android.settings.development.bluetooth.BluetoothChannelModeDialogPreferenceController;
|
import com.android.settings.development.bluetooth.BluetoothChannelModeDialogPreferenceController;
|
||||||
import com.android.settings.development.bluetooth.BluetoothCodecDialogPreferenceController;
|
import com.android.settings.development.bluetooth.BluetoothCodecDialogPreferenceController;
|
||||||
|
import com.android.settings.development.bluetooth.BluetoothCodecListPreferenceController;
|
||||||
import com.android.settings.development.bluetooth.BluetoothHDAudioPreferenceController;
|
import com.android.settings.development.bluetooth.BluetoothHDAudioPreferenceController;
|
||||||
import com.android.settings.development.bluetooth.BluetoothQualityDialogPreferenceController;
|
import com.android.settings.development.bluetooth.BluetoothQualityDialogPreferenceController;
|
||||||
import com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreferenceController;
|
import com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreferenceController;
|
||||||
@@ -744,6 +746,9 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
|||||||
controllers.add(new AutofillResetOptionsPreferenceController(context));
|
controllers.add(new AutofillResetOptionsPreferenceController(context));
|
||||||
controllers.add(new BluetoothCodecDialogPreferenceController(context, lifecycle,
|
controllers.add(new BluetoothCodecDialogPreferenceController(context, lifecycle,
|
||||||
bluetoothA2dpConfigStore, fragment));
|
bluetoothA2dpConfigStore, fragment));
|
||||||
|
controllers.add(
|
||||||
|
new BluetoothCodecListPreferenceController(
|
||||||
|
context, lifecycle, bluetoothA2dpConfigStore, fragment));
|
||||||
controllers.add(new BluetoothSampleRateDialogPreferenceController(context, lifecycle,
|
controllers.add(new BluetoothSampleRateDialogPreferenceController(context, lifecycle,
|
||||||
bluetoothA2dpConfigStore));
|
bluetoothA2dpConfigStore));
|
||||||
controllers.add(new BluetoothBitPerSampleDialogPreferenceController(context, lifecycle,
|
controllers.add(new BluetoothBitPerSampleDialogPreferenceController(context, lifecycle,
|
||||||
@@ -792,6 +797,9 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
|||||||
((AbstractBluetoothDialogPreferenceController) controller).onHDAudioEnabled(
|
((AbstractBluetoothDialogPreferenceController) controller).onHDAudioEnabled(
|
||||||
enabled);
|
enabled);
|
||||||
}
|
}
|
||||||
|
if (controller instanceof AbstractBluetoothListPreferenceController) {
|
||||||
|
((AbstractBluetoothListPreferenceController) controller).onHDAudioEnabled(enabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development.bluetooth;
|
||||||
|
|
||||||
|
import static android.bluetooth.BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothA2dp;
|
||||||
|
import android.bluetooth.BluetoothCodecConfig;
|
||||||
|
import android.bluetooth.BluetoothCodecStatus;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.preference.ListPreference;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.development.BluetoothA2dpConfigStore;
|
||||||
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Abstract class for Bluetooth A2DP config list controller in developer option. */
|
||||||
|
public abstract class AbstractBluetoothListPreferenceController
|
||||||
|
extends AbstractBluetoothPreferenceController
|
||||||
|
implements Preference.OnPreferenceChangeListener {
|
||||||
|
|
||||||
|
private static final String TAG = "AbstrBtListPrefCtrl";
|
||||||
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
|
protected static final int DEFAULT_VALUE_INT = 1000;
|
||||||
|
|
||||||
|
@Nullable protected ListPreference mListPreference;
|
||||||
|
|
||||||
|
protected String mDefaultEntry;
|
||||||
|
protected String mDefaultValue;
|
||||||
|
|
||||||
|
@Nullable protected final BluetoothA2dpConfigStore mBluetoothA2dpConfigStore;
|
||||||
|
|
||||||
|
public AbstractBluetoothListPreferenceController(
|
||||||
|
@NonNull Context context,
|
||||||
|
@Nullable Lifecycle lifecycle,
|
||||||
|
@Nullable BluetoothA2dpConfigStore store) {
|
||||||
|
super(context, lifecycle, store);
|
||||||
|
|
||||||
|
mDefaultEntry = mContext.getString(R.string.bluetooth_audio_codec_default_selection);
|
||||||
|
mDefaultValue = String.valueOf(DEFAULT_VALUE_INT);
|
||||||
|
|
||||||
|
mBluetoothA2dpConfigStore = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(@NonNull PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
mListPreference = screen.findPreference(getPreferenceKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(@Nullable Preference preference, @NonNull Object newValue) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "onPreferenceChange: newValue=" + (String) newValue);
|
||||||
|
}
|
||||||
|
if (mListPreference == null) {
|
||||||
|
Log.e(TAG, "onPreferenceChange: List preference is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
updateState(mListPreference);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(@Nullable Preference preference) {
|
||||||
|
setupDefaultListPreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBluetoothServiceConnected(@NonNull BluetoothA2dp bluetoothA2dp) {
|
||||||
|
super.onBluetoothServiceConnected(bluetoothA2dp);
|
||||||
|
initConfigStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDeveloperOptionsSwitchDisabled() {
|
||||||
|
super.onDeveloperOptionsSwitchDisabled();
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "onDeveloperOptionsSwitchDisabled");
|
||||||
|
}
|
||||||
|
if (mListPreference == null) {
|
||||||
|
Log.e(TAG, "onDeveloperOptionsSwitchDisabled: List preference is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateState(mListPreference);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to notify controller when the HD audio(optional codec) state is changed.
|
||||||
|
*
|
||||||
|
* @param enabled Is {@code true} when the setting is enabled.
|
||||||
|
*/
|
||||||
|
public void onHDAudioEnabled(boolean enabled) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the new value to the {@link BluetoothA2dpConfigStore}.
|
||||||
|
*
|
||||||
|
* @param entryValue the new setting entry value
|
||||||
|
*/
|
||||||
|
protected abstract void writeConfigurationValues(String entryValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current bluetooth codec status.
|
||||||
|
*
|
||||||
|
* @return {@link BluetoothCodecStatus}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
protected BluetoothCodecStatus getBluetoothCodecStatus() {
|
||||||
|
final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp;
|
||||||
|
if (bluetoothA2dp == null) {
|
||||||
|
Log.e(
|
||||||
|
TAG,
|
||||||
|
"getBluetoothCodecStatus: Unable to get codec status. Bluetooth A2dp is null.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final BluetoothDevice activeDevice = getA2dpActiveDevice();
|
||||||
|
if (activeDevice == null) {
|
||||||
|
Log.e(TAG, "getBluetoothCodecStatus: Unable to get codec status. No active device.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final BluetoothCodecStatus codecStatus = bluetoothA2dp.getCodecStatus(activeDevice);
|
||||||
|
if (codecStatus == null) {
|
||||||
|
Log.e(TAG, "getBluetoothCodecStatus: Codec status is null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return codecStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current bluetooth codec config.
|
||||||
|
*
|
||||||
|
* @return {@link BluetoothCodecConfig}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
protected BluetoothCodecConfig getCurrentCodecConfig() {
|
||||||
|
final BluetoothCodecStatus codecStatus = getBluetoothCodecStatus();
|
||||||
|
if (codecStatus == null) {
|
||||||
|
Log.e(
|
||||||
|
TAG,
|
||||||
|
"getCurrentCodecConfig: Unable to get current codec config. Codec status is"
|
||||||
|
+ " null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return codecStatus.getCodecConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link ListPreference}. This method adds the default entry and the entry value
|
||||||
|
* automatically.
|
||||||
|
*
|
||||||
|
* @param entries list of String entries for the {@link ListPreference}.
|
||||||
|
* @param entryValues list of String entry values for the {@link ListPreference}.
|
||||||
|
* @param selectedEntry currently selected entry.
|
||||||
|
* @param selectedValue currently selected entry value.
|
||||||
|
*/
|
||||||
|
protected void setupListPreference(
|
||||||
|
List<String> entries,
|
||||||
|
List<String> entryValues,
|
||||||
|
String selectedEntry,
|
||||||
|
String selectedValue) {
|
||||||
|
if (entries.size() != entryValues.size()) {
|
||||||
|
Log.e(
|
||||||
|
TAG,
|
||||||
|
("setupListPreference: size of entries: " + entries.size())
|
||||||
|
+ (", size of entryValues" + entryValues.size()));
|
||||||
|
setupDefaultListPreference();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (entries.isEmpty() || entryValues.isEmpty()) {
|
||||||
|
Log.e(TAG, "setupListPreference: entries or entryValues empty");
|
||||||
|
setupDefaultListPreference();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entries.add(0, mDefaultEntry);
|
||||||
|
entryValues.add(0, mDefaultValue);
|
||||||
|
|
||||||
|
if (mListPreference == null) {
|
||||||
|
Log.e(TAG, "setupListPreference: List preference is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mListPreference.setEntries(entries.toArray(new String[entries.size()]));
|
||||||
|
mListPreference.setEntryValues(entryValues.toArray(new String[entryValues.size()]));
|
||||||
|
mListPreference.setValue(selectedValue);
|
||||||
|
mListPreference.setSummary(selectedEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check HD Audio enabled.
|
||||||
|
*
|
||||||
|
* @return true if HD Audio is enabled.
|
||||||
|
*/
|
||||||
|
protected boolean isHDAudioEnabled() {
|
||||||
|
final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp;
|
||||||
|
if (bluetoothA2dp == null) {
|
||||||
|
Log.e(TAG, "isHDAudioEnabled: Unable to get codec status. BluetoothA2dp is null.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BluetoothDevice activeDevice = getA2dpActiveDevice();
|
||||||
|
if (activeDevice == null) {
|
||||||
|
Log.e(TAG, "isHDAudioEnabled: Unable to get codec status. No active device.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (bluetoothA2dp.isOptionalCodecsEnabled(activeDevice)
|
||||||
|
== BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupDefaultListPreference() {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"setupDefaultListPreference: mDefaultEntry="
|
||||||
|
+ mDefaultEntry
|
||||||
|
+ ", mDefaultValue="
|
||||||
|
+ mDefaultValue);
|
||||||
|
}
|
||||||
|
if (mListPreference == null) {
|
||||||
|
Log.e(TAG, "setupListPreference: List preference is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mListPreference.setEntries(new String[] {mDefaultEntry});
|
||||||
|
mListPreference.setEntryValues(new String[] {mDefaultValue});
|
||||||
|
mListPreference.setValue(mDefaultValue);
|
||||||
|
mListPreference.setSummary(mDefaultEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initConfigStore() {
|
||||||
|
final BluetoothCodecConfig config = getCurrentCodecConfig();
|
||||||
|
if (config == null) {
|
||||||
|
Log.e(TAG, "initConfigStore: Current codec config is null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mBluetoothA2dpConfigStore == null) {
|
||||||
|
Log.e(TAG, "initConfigStore: Bluetooth A2dp Config Store is null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mBluetoothA2dpConfigStore.setCodecType(config.getExtendedCodecType());
|
||||||
|
mBluetoothA2dpConfigStore.setSampleRate(config.getSampleRate());
|
||||||
|
mBluetoothA2dpConfigStore.setBitsPerSample(config.getBitsPerSample());
|
||||||
|
mBluetoothA2dpConfigStore.setChannelMode(config.getChannelMode());
|
||||||
|
mBluetoothA2dpConfigStore.setCodecPriority(CODEC_PRIORITY_HIGHEST);
|
||||||
|
mBluetoothA2dpConfigStore.setCodecSpecific1Value(config.getCodecSpecific1());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import android.bluetooth.BluetoothManager;
|
|||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.settings.core.PreferenceControllerMixin;
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
@@ -42,13 +43,15 @@ public abstract class AbstractBluetoothPreferenceController extends
|
|||||||
DeveloperOptionsPreferenceController implements BluetoothServiceConnectionListener,
|
DeveloperOptionsPreferenceController implements BluetoothServiceConnectionListener,
|
||||||
LifecycleObserver, OnDestroy, PreferenceControllerMixin {
|
LifecycleObserver, OnDestroy, PreferenceControllerMixin {
|
||||||
|
|
||||||
protected volatile BluetoothA2dp mBluetoothA2dp;
|
@Nullable protected volatile BluetoothA2dp mBluetoothA2dp;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BluetoothAdapter mBluetoothAdapter;
|
BluetoothAdapter mBluetoothAdapter;
|
||||||
|
|
||||||
public AbstractBluetoothPreferenceController(Context context, Lifecycle lifecycle,
|
public AbstractBluetoothPreferenceController(
|
||||||
BluetoothA2dpConfigStore store) {
|
@Nullable Context context,
|
||||||
|
@Nullable Lifecycle lifecycle,
|
||||||
|
@Nullable BluetoothA2dpConfigStore store) {
|
||||||
super(context);
|
super(context);
|
||||||
if (lifecycle != null) {
|
if (lifecycle != null) {
|
||||||
lifecycle.addObserver(this);
|
lifecycle.addObserver(this);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.development.BluetoothA2dpConfigStore;
|
import com.android.settings.development.BluetoothA2dpConfigStore;
|
||||||
|
import com.android.settings.development.Flags;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -49,6 +50,11 @@ public class BluetoothCodecDialogPreferenceController extends
|
|||||||
mCallback = callback;
|
mCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return !Flags.a2dpOffloadCodecExtensibilitySettings();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPreferenceKey() {
|
public String getPreferenceKey() {
|
||||||
return KEY;
|
return KEY;
|
||||||
|
|||||||
@@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development.bluetooth;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothA2dp;
|
||||||
|
import android.bluetooth.BluetoothCodecConfig;
|
||||||
|
import android.bluetooth.BluetoothCodecStatus;
|
||||||
|
import android.bluetooth.BluetoothCodecType;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.development.BluetoothA2dpConfigStore;
|
||||||
|
import com.android.settings.development.Flags;
|
||||||
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** List preference controller to set the Bluetooth A2DP codec */
|
||||||
|
public class BluetoothCodecListPreferenceController
|
||||||
|
extends AbstractBluetoothListPreferenceController {
|
||||||
|
|
||||||
|
private static final String KEY = "bluetooth_audio_codec_settings_list";
|
||||||
|
private static final String TAG = "BtExtCodecCtr";
|
||||||
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
|
@Nullable private final Callback mCallback;
|
||||||
|
|
||||||
|
public BluetoothCodecListPreferenceController(
|
||||||
|
@NonNull Context context,
|
||||||
|
@Nullable Lifecycle lifecycle,
|
||||||
|
@Nullable BluetoothA2dpConfigStore store,
|
||||||
|
@Nullable Callback callback) {
|
||||||
|
super(context, lifecycle, store);
|
||||||
|
mCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
boolean available = Flags.a2dpOffloadCodecExtensibilitySettings();
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "isAvailable: " + available);
|
||||||
|
}
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull String getPreferenceKey() {
|
||||||
|
return KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(@NonNull PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
mListPreference = screen.findPreference(getPreferenceKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(@Nullable Preference preference, @NonNull Object newValue) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "onPreferenceChange: newValue=" + (String) newValue);
|
||||||
|
}
|
||||||
|
final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp;
|
||||||
|
if (bluetoothA2dp == null) {
|
||||||
|
Log.e(TAG, "onPreferenceChange: bluetoothA2dp is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeConfigurationValues((String) newValue);
|
||||||
|
|
||||||
|
if (mBluetoothA2dpConfigStore == null) {
|
||||||
|
Log.e(TAG, "onPreferenceChange: Bluetooth A2dp Config Store is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BluetoothCodecConfig codecConfig;
|
||||||
|
if (Flags.a2dpOffloadCodecExtensibilitySettings()) {
|
||||||
|
codecConfig = mBluetoothA2dpConfigStore.createCodecConfigFromCodecType();
|
||||||
|
} else {
|
||||||
|
codecConfig = mBluetoothA2dpConfigStore.createCodecConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
final BluetoothDevice activeDevice = getA2dpActiveDevice();
|
||||||
|
if (activeDevice == null) {
|
||||||
|
Log.e(TAG, "onPreferenceChange: active device is null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "onPreferenceChange: setCodecConfigPreference: " + codecConfig.toString());
|
||||||
|
}
|
||||||
|
bluetoothA2dp.setCodecConfigPreference(activeDevice, codecConfig);
|
||||||
|
if (mCallback != null) {
|
||||||
|
mCallback.onBluetoothCodecChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(@Nullable Preference preference) {
|
||||||
|
super.updateState(preference);
|
||||||
|
final List<String> codecIds = new ArrayList<>();
|
||||||
|
final List<String> labels = new ArrayList<>();
|
||||||
|
String selectedCodecId = mDefaultValue;
|
||||||
|
String selectedLabel = mDefaultEntry;
|
||||||
|
|
||||||
|
if (isHDAudioEnabled()) {
|
||||||
|
final BluetoothCodecStatus codecStatus = getBluetoothCodecStatus();
|
||||||
|
if (codecStatus == null) {
|
||||||
|
Log.e(TAG, "updateState: Bluetooth Codec Status is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final BluetoothCodecConfig currentCodecConfig = codecStatus.getCodecConfig();
|
||||||
|
if (currentCodecConfig == null) {
|
||||||
|
Log.e(TAG, "updateState: currentCodecConfig is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp;
|
||||||
|
if (bluetoothA2dp == null) {
|
||||||
|
Log.e(TAG, "updateState: bluetoothA2dp is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Collection<BluetoothCodecType> codecTypes =
|
||||||
|
bluetoothA2dp.getSupportedCodecTypes();
|
||||||
|
for (BluetoothCodecType codecType : codecTypes) {
|
||||||
|
labels.add(codecType.getCodecName());
|
||||||
|
codecIds.add(String.valueOf(codecType.getCodecId()));
|
||||||
|
if (currentCodecConfig != null
|
||||||
|
&& currentCodecConfig.getExtendedCodecType().equals(codecType)) {
|
||||||
|
selectedCodecId = codecIds.get(codecIds.size() - 1);
|
||||||
|
selectedLabel = labels.get(labels.size() - 1);
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"updateState: Current config: "
|
||||||
|
+ selectedLabel
|
||||||
|
+ ", id: "
|
||||||
|
+ selectedCodecId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupListPreference(labels, codecIds, selectedLabel, selectedCodecId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHDAudioEnabled(boolean enabled) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "onHDAudioEnabled: enabled=" + enabled);
|
||||||
|
}
|
||||||
|
if (mListPreference == null) {
|
||||||
|
Log.e(TAG, "onHDAudioEnabled: List preference is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mListPreference.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeConfigurationValues(String entryValue) {
|
||||||
|
long codecIdValue = getCodecIdFromEntryValue(entryValue);
|
||||||
|
BluetoothCodecType selectedCodecType = null;
|
||||||
|
BluetoothCodecConfig selectedCodecConfig = null;
|
||||||
|
|
||||||
|
final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp;
|
||||||
|
if (bluetoothA2dp == null) {
|
||||||
|
Log.e(TAG, "writeConfigurationValues: bluetoothA2dp is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Collection<BluetoothCodecType> codecTypes = bluetoothA2dp.getSupportedCodecTypes();
|
||||||
|
for (BluetoothCodecType codecType : codecTypes) {
|
||||||
|
if (codecType.getCodecId() == codecIdValue) {
|
||||||
|
selectedCodecType = codecType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedCodecType == null) {
|
||||||
|
Log.e(
|
||||||
|
TAG,
|
||||||
|
"writeConfigurationValues: No selectable codec ID: "
|
||||||
|
+ codecIdValue
|
||||||
|
+ " found. Unable to change codec");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "writeConfigurationValues: Selected codec: " + selectedCodecType.toString());
|
||||||
|
}
|
||||||
|
final BluetoothCodecStatus codecStatus = getBluetoothCodecStatus();
|
||||||
|
if (codecStatus == null) {
|
||||||
|
Log.e(TAG, "writeConfigurationValues: Bluetooth Codec Status is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<BluetoothCodecConfig> codecConfigs =
|
||||||
|
codecStatus.getCodecsSelectableCapabilities();
|
||||||
|
for (BluetoothCodecConfig config : codecConfigs) {
|
||||||
|
BluetoothCodecType codecType = config.getExtendedCodecType();
|
||||||
|
if (codecType == null) {
|
||||||
|
Log.e(TAG, "codec type for config:" + config + " is null");
|
||||||
|
}
|
||||||
|
if (codecType != null && codecType.equals(selectedCodecType)) {
|
||||||
|
selectedCodecConfig = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedCodecConfig == null) {
|
||||||
|
Log.e(
|
||||||
|
TAG,
|
||||||
|
"writeConfigurationValues: No selectable codec config for codec: "
|
||||||
|
+ selectedCodecType.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBluetoothA2dpConfigStore == null) {
|
||||||
|
Log.e(TAG, "writeConfigurationValues: Bluetooth A2dp Config Store is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mBluetoothA2dpConfigStore.setCodecType(selectedCodecType);
|
||||||
|
mBluetoothA2dpConfigStore.setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST);
|
||||||
|
mBluetoothA2dpConfigStore.setSampleRate(
|
||||||
|
AbstractBluetoothDialogPreferenceController.getHighestSampleRate(
|
||||||
|
selectedCodecConfig));
|
||||||
|
mBluetoothA2dpConfigStore.setBitsPerSample(
|
||||||
|
AbstractBluetoothDialogPreferenceController.getHighestBitsPerSample(
|
||||||
|
selectedCodecConfig));
|
||||||
|
mBluetoothA2dpConfigStore.setChannelMode(
|
||||||
|
AbstractBluetoothDialogPreferenceController.getHighestChannelMode(
|
||||||
|
selectedCodecConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getCodecIdFromEntryValue(String entryValue) {
|
||||||
|
long codecType = BluetoothCodecType.CODEC_ID_SBC;
|
||||||
|
if (entryValue.isEmpty() || Long.valueOf(entryValue) == DEFAULT_VALUE_INT) {
|
||||||
|
return codecType;
|
||||||
|
}
|
||||||
|
return Long.valueOf(entryValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,8 @@ import android.hardware.display.DisplayManager.DisplayListener;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.Process;
|
||||||
|
import android.os.UserManager;
|
||||||
import android.provider.Settings.System;
|
import android.provider.Settings.System;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
@@ -116,6 +118,10 @@ public class BrightnessLevelPreferenceController extends AbstractPreferenceContr
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateState(Preference preference) {
|
public void updateState(Preference preference) {
|
||||||
|
if (preference.isEnabled() && UserManager.get(mContext).hasBaseUserRestriction(
|
||||||
|
UserManager.DISALLOW_CONFIG_BRIGHTNESS, Process.myUserHandle())) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
}
|
||||||
updatedSummary(preference);
|
updatedSummary(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import static com.android.settings.display.ScreenTimeoutSettings.FALLBACK_SCREEN
|
|||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Process;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -67,9 +68,13 @@ public class ScreenTimeoutPreferenceController extends BasePreferenceController
|
|||||||
.getString(DISABLED_BY_IT_ADMIN_TITLE,
|
.getString(DISABLED_BY_IT_ADMIN_TITLE,
|
||||||
() -> mContext.getString(R.string.disabled_by_policy_title)));
|
() -> mContext.getString(R.string.disabled_by_policy_title)));
|
||||||
((RestrictedPreference) preference).setDisabledByAdmin(admin);
|
((RestrictedPreference) preference).setDisabledByAdmin(admin);
|
||||||
} else {
|
return;
|
||||||
preference.setSummary(getTimeoutSummary(maxTimeout));
|
|
||||||
}
|
}
|
||||||
|
if (UserManager.get(mContext).hasBaseUserRestriction(
|
||||||
|
UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, Process.myUserHandle())) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
}
|
||||||
|
preference.setSummary(getTimeoutSummary(maxTimeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CharSequence getTimeoutSummary(long maxTimeout) {
|
private CharSequence getTimeoutSummary(long maxTimeout) {
|
||||||
|
|||||||
@@ -927,34 +927,45 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
|
switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
|
||||||
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
|
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
|
||||||
if (hasFingerprints && hasFace) {
|
if (hasFingerprints && hasFace) {
|
||||||
return R.string.unlock_disable_frp_warning_content_pattern_face_fingerprint;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_face_fingerprint_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_pattern_face_fingerprint;
|
||||||
} else if (hasFingerprints) {
|
} else if (hasFingerprints) {
|
||||||
return R.string.unlock_disable_frp_warning_content_pattern_fingerprint;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_fingerprint_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_pattern_fingerprint;
|
||||||
} else if (hasFace) {
|
} else if (hasFace) {
|
||||||
return R.string.unlock_disable_frp_warning_content_pattern_face;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_face_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_pattern_face;
|
||||||
} else {
|
} else {
|
||||||
return R.string.unlock_disable_frp_warning_content_pattern;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
? R.string.unlock_disable_frp_warning_content_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_pattern;
|
||||||
}
|
}
|
||||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
|
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
|
||||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
|
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
|
||||||
if (hasFingerprints && hasFace) {
|
if (hasFingerprints && hasFace) {
|
||||||
return hasAppsWithAuthBoundKeys
|
return hasAppsWithAuthBoundKeys
|
||||||
?
|
?
|
||||||
R.string.unlock_disable_frp_warning_content_pin_face_fingerprint_authbound_keys
|
R.string.unlock_disable_frp_warning_content_face_fingerprint_authbound_keys
|
||||||
: R.string.unlock_disable_frp_warning_content_pin_face_fingerprint;
|
: R.string.unlock_disable_frp_warning_content_pin_face_fingerprint;
|
||||||
} else if (hasFingerprints) {
|
} else if (hasFingerprints) {
|
||||||
return hasAppsWithAuthBoundKeys
|
return hasAppsWithAuthBoundKeys
|
||||||
?
|
?
|
||||||
R.string.unlock_disable_frp_warning_content_pin_fingerprint_authbound_keys
|
R.string.unlock_disable_frp_warning_content_fingerprint_authbound_keys
|
||||||
: R.string.unlock_disable_frp_warning_content_pin_fingerprint;
|
: R.string.unlock_disable_frp_warning_content_pin_fingerprint;
|
||||||
} else if (hasFace) {
|
} else if (hasFace) {
|
||||||
return hasAppsWithAuthBoundKeys
|
return hasAppsWithAuthBoundKeys
|
||||||
?
|
?
|
||||||
R.string.unlock_disable_frp_warning_content_pin_face_authbound_keys
|
R.string.unlock_disable_frp_warning_content_face_authbound_keys
|
||||||
: R.string.unlock_disable_frp_warning_content_pin_face;
|
: R.string.unlock_disable_frp_warning_content_pin_face;
|
||||||
} else {
|
} else {
|
||||||
return hasAppsWithAuthBoundKeys
|
return hasAppsWithAuthBoundKeys
|
||||||
? R.string.unlock_disable_frp_warning_content_pin_authbound_keys
|
? R.string.unlock_disable_frp_warning_content_authbound_keys
|
||||||
: R.string.unlock_disable_frp_warning_content_pin;
|
: R.string.unlock_disable_frp_warning_content_pin;
|
||||||
}
|
}
|
||||||
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
|
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
|
||||||
@@ -962,24 +973,45 @@ public class ChooseLockGeneric extends SettingsActivity {
|
|||||||
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
|
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
|
||||||
case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
|
case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
|
||||||
if (hasFingerprints && hasFace) {
|
if (hasFingerprints && hasFace) {
|
||||||
return R.string
|
return hasAppsWithAuthBoundKeys
|
||||||
.unlock_disable_frp_warning_content_password_face_fingerprint;
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_face_fingerprint_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_password_face_fingerprint;
|
||||||
} else if (hasFingerprints) {
|
} else if (hasFingerprints) {
|
||||||
return R.string.unlock_disable_frp_warning_content_password_fingerprint;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_fingerprint_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_password_fingerprint;
|
||||||
} else if (hasFace) {
|
} else if (hasFace) {
|
||||||
return R.string.unlock_disable_frp_warning_content_password_face;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_face_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_password_face;
|
||||||
} else {
|
} else {
|
||||||
return R.string.unlock_disable_frp_warning_content_password;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
? R.string.unlock_disable_frp_warning_content_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_password;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if (hasFingerprints && hasFace) {
|
if (hasFingerprints && hasFace) {
|
||||||
return R.string.unlock_disable_frp_warning_content_unknown_face_fingerprint;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_face_fingerprint_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_unknown_face_fingerprint;
|
||||||
} else if (hasFingerprints) {
|
} else if (hasFingerprints) {
|
||||||
return R.string.unlock_disable_frp_warning_content_unknown_fingerprint;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_fingerprint_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_unknown_fingerprint;
|
||||||
} else if (hasFace) {
|
} else if (hasFace) {
|
||||||
return R.string.unlock_disable_frp_warning_content_unknown_face;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
?
|
||||||
|
R.string.unlock_disable_frp_warning_content_face_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_unknown_face;
|
||||||
} else {
|
} else {
|
||||||
return R.string.unlock_disable_frp_warning_content_unknown;
|
return hasAppsWithAuthBoundKeys
|
||||||
|
? R.string.unlock_disable_frp_warning_content_authbound_keys
|
||||||
|
: R.string.unlock_disable_frp_warning_content_unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.platform.test.annotations.RequiresFlagsDisabled;
|
import android.platform.test.annotations.DisableFlags;
|
||||||
import android.platform.test.annotations.RequiresFlagsEnabled;
|
import android.platform.test.annotations.EnableFlags;
|
||||||
import android.platform.test.flag.junit.CheckFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
import android.provider.Settings;
|
||||||
import android.service.quicksettings.TileService;
|
import android.service.quicksettings.TileService;
|
||||||
import android.view.accessibility.AccessibilityManager;
|
import android.view.accessibility.AccessibilityManager;
|
||||||
import android.view.accessibility.Flags;
|
import android.view.accessibility.Flags;
|
||||||
@@ -47,6 +47,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.internal.accessibility.common.ShortcutConstants;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
|
||||||
@@ -68,13 +69,13 @@ import org.robolectric.shadows.ShadowAccessibilityManager;
|
|||||||
import org.robolectric.shadows.ShadowPackageManager;
|
import org.robolectric.shadows.ShadowPackageManager;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/** Tests for {@link ToggleAccessibilityServicePreferenceFragment} */
|
/** Tests for {@link ToggleAccessibilityServicePreferenceFragment} */
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class ToggleAccessibilityServicePreferenceFragmentTest {
|
public class ToggleAccessibilityServicePreferenceFragmentTest {
|
||||||
|
|
||||||
@Rule
|
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
|
|
||||||
|
|
||||||
private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
|
private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
|
||||||
private static final String PLACEHOLDER_PACKAGE_NAME2 = "com.placeholder.example2";
|
private static final String PLACEHOLDER_PACKAGE_NAME2 = "com.placeholder.example2";
|
||||||
@@ -236,7 +237,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
@EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
||||||
public void enableService_warningRequired_showWarning() throws Throwable {
|
public void enableService_warningRequired_showWarning() throws Throwable {
|
||||||
setupServiceWarningRequired(true);
|
setupServiceWarningRequired(true);
|
||||||
mFragment.mToggleServiceSwitchPreference =
|
mFragment.mToggleServiceSwitchPreference =
|
||||||
@@ -249,7 +250,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
@EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
||||||
public void enableService_warningNotRequired_dontShowWarning() throws Throwable {
|
public void enableService_warningNotRequired_dontShowWarning() throws Throwable {
|
||||||
final AccessibilityServiceInfo info = setupServiceWarningRequired(false);
|
final AccessibilityServiceInfo info = setupServiceWarningRequired(false);
|
||||||
mFragment.mToggleServiceSwitchPreference =
|
mFragment.mToggleServiceSwitchPreference =
|
||||||
@@ -263,7 +264,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
@EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
||||||
public void toggleShortcutPreference_warningRequired_showWarning() throws Throwable {
|
public void toggleShortcutPreference_warningRequired_showWarning() throws Throwable {
|
||||||
setupServiceWarningRequired(true);
|
setupServiceWarningRequired(true);
|
||||||
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null);
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null);
|
||||||
@@ -277,7 +278,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
@EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
||||||
public void toggleShortcutPreference_warningNotRequired_dontShowWarning() throws Throwable {
|
public void toggleShortcutPreference_warningNotRequired_dontShowWarning() throws Throwable {
|
||||||
setupServiceWarningRequired(false);
|
setupServiceWarningRequired(false);
|
||||||
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null);
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null);
|
||||||
@@ -291,7 +292,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
@EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
||||||
public void clickShortcutSettingsPreference_warningRequired_showWarning() throws Throwable {
|
public void clickShortcutSettingsPreference_warningRequired_showWarning() throws Throwable {
|
||||||
setupServiceWarningRequired(true);
|
setupServiceWarningRequired(true);
|
||||||
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null);
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null);
|
||||||
@@ -303,8 +304,8 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
@EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
||||||
@RequiresFlagsDisabled(
|
@DisableFlags(
|
||||||
com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN)
|
com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN)
|
||||||
public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_showDialog()
|
public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_showDialog()
|
||||||
throws Throwable {
|
throws Throwable {
|
||||||
@@ -318,7 +319,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresFlagsEnabled({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG,
|
@EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG,
|
||||||
com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN})
|
com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN})
|
||||||
public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_launchActivity()
|
public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_launchActivity()
|
||||||
throws Throwable {
|
throws Throwable {
|
||||||
@@ -334,6 +335,155 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
|
|||||||
.isEqualTo(EditShortcutsPreferenceFragment.class.getName());
|
.isEqualTo(EditShortcutsPreferenceFragment.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDefaultShortcutTypes_noAssociatedTile_softwareTypeIsDefault() {
|
||||||
|
PreferredShortcuts.clearPreferredShortcuts(mContext);
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(null);
|
||||||
|
|
||||||
|
assertThat(mFragment.getDefaultShortcutTypes())
|
||||||
|
.isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
|
||||||
|
public void getDefaultShortcutTypes_hasAssociatedTile_qsTypeIsDefault() {
|
||||||
|
PreferredShortcuts.clearPreferredShortcuts(mContext);
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME);
|
||||||
|
|
||||||
|
assertThat(mFragment.getDefaultShortcutTypes())
|
||||||
|
.isEqualTo(ShortcutConstants.UserShortcutType.QUICK_SETTINGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
|
||||||
|
public void getDefaultShortcutTypes_hasAssociatedTile_softwareTypeIsDefault() {
|
||||||
|
PreferredShortcuts.clearPreferredShortcuts(mContext);
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME);
|
||||||
|
|
||||||
|
assertThat(mFragment.getDefaultShortcutTypes())
|
||||||
|
.isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, Flags.FLAG_A11Y_QS_SHORTCUT})
|
||||||
|
public void toggleShortcutPreference_noUserPreferredShortcut_hasQsTile_enableQsShortcut()
|
||||||
|
throws Throwable {
|
||||||
|
PreferredShortcuts.clearPreferredShortcuts(mContext);
|
||||||
|
setupServiceWarningRequired(false);
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME);
|
||||||
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null);
|
||||||
|
|
||||||
|
mFragment.mShortcutPreference.setChecked(true);
|
||||||
|
mFragment.onToggleClicked(mFragment.mShortcutPreference);
|
||||||
|
|
||||||
|
verify(mMockAccessibilityManager)
|
||||||
|
.enableShortcutsForTargets(true,
|
||||||
|
ShortcutConstants.UserShortcutType.QUICK_SETTINGS,
|
||||||
|
Set.of(mFragment.mComponentName.flattenToString()), mContext.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, Flags.FLAG_A11Y_QS_SHORTCUT})
|
||||||
|
public void toggleShortcutPreference_noUserPreferredShortcut_noQsTile_enableSoftwareShortcut()
|
||||||
|
throws Throwable {
|
||||||
|
PreferredShortcuts.clearPreferredShortcuts(mContext);
|
||||||
|
setupServiceWarningRequired(false);
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(null);
|
||||||
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null);
|
||||||
|
|
||||||
|
mFragment.mShortcutPreference.setChecked(true);
|
||||||
|
mFragment.onToggleClicked(mFragment.mShortcutPreference);
|
||||||
|
|
||||||
|
verify(mMockAccessibilityManager)
|
||||||
|
.enableShortcutsForTargets(true,
|
||||||
|
ShortcutConstants.UserShortcutType.SOFTWARE,
|
||||||
|
Set.of(mFragment.mComponentName.flattenToString()), mContext.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
||||||
|
@DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
|
||||||
|
public void toggleShortcutPreference_noUserPreferredShortcut_hasQsTile_flagOff_enableSoftwareShortcut()
|
||||||
|
throws Throwable {
|
||||||
|
PreferredShortcuts.clearPreferredShortcuts(mContext);
|
||||||
|
setupServiceWarningRequired(false);
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME);
|
||||||
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null);
|
||||||
|
|
||||||
|
mFragment.mShortcutPreference.setChecked(true);
|
||||||
|
mFragment.onToggleClicked(mFragment.mShortcutPreference);
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
Settings.Secure.getString(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS))
|
||||||
|
.contains(mFragment.mComponentName.flattenToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
|
||||||
|
@DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
|
||||||
|
public void toggleShortcutPreference_noUserPreferredShortcut_noQsTile_flagOff_enableSoftwareShortcut()
|
||||||
|
throws Throwable {
|
||||||
|
PreferredShortcuts.clearPreferredShortcuts(mContext);
|
||||||
|
setupServiceWarningRequired(false);
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(null);
|
||||||
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null);
|
||||||
|
|
||||||
|
mFragment.mShortcutPreference.setChecked(true);
|
||||||
|
mFragment.onToggleClicked(mFragment.mShortcutPreference);
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
Settings.Secure.getString(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS))
|
||||||
|
.contains(mFragment.mComponentName.flattenToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, Flags.FLAG_A11Y_QS_SHORTCUT})
|
||||||
|
public void toggleShortcutPreference_userPreferVolumeKeysShortcut_noQsTile_enableVolumeKeysShortcut()
|
||||||
|
throws Throwable {
|
||||||
|
setupServiceWarningRequired(false);
|
||||||
|
String componentName = mFragment.mComponentName.flattenToString();
|
||||||
|
PreferredShortcuts.saveUserShortcutType(
|
||||||
|
mContext,
|
||||||
|
new PreferredShortcut(componentName, ShortcutConstants.UserShortcutType.HARDWARE));
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(null);
|
||||||
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null);
|
||||||
|
|
||||||
|
mFragment.mShortcutPreference.setChecked(true);
|
||||||
|
mFragment.onToggleClicked(mFragment.mShortcutPreference);
|
||||||
|
|
||||||
|
verify(mMockAccessibilityManager)
|
||||||
|
.enableShortcutsForTargets(
|
||||||
|
true,
|
||||||
|
ShortcutConstants.UserShortcutType.HARDWARE,
|
||||||
|
Set.of(componentName),
|
||||||
|
mContext.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, Flags.FLAG_A11Y_QS_SHORTCUT})
|
||||||
|
public void toggleShortcutPreference_userPreferVolumeKeysShortcut_hasQsTile_enableVolumeKeysShortcut()
|
||||||
|
throws Throwable {
|
||||||
|
setupServiceWarningRequired(false);
|
||||||
|
String componentName = mFragment.mComponentName.flattenToString();
|
||||||
|
PreferredShortcuts.saveUserShortcutType(
|
||||||
|
mContext,
|
||||||
|
new PreferredShortcut(componentName, ShortcutConstants.UserShortcutType.HARDWARE));
|
||||||
|
when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME);
|
||||||
|
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null);
|
||||||
|
|
||||||
|
mFragment.mShortcutPreference.setChecked(true);
|
||||||
|
mFragment.onToggleClicked(mFragment.mShortcutPreference);
|
||||||
|
|
||||||
|
verify(mMockAccessibilityManager)
|
||||||
|
.enableShortcutsForTargets(
|
||||||
|
true,
|
||||||
|
ShortcutConstants.UserShortcutType.HARDWARE,
|
||||||
|
Set.of(componentName),
|
||||||
|
mContext.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
private void setupTileService(String packageName, String name, String tileName) {
|
private void setupTileService(String packageName, String name, String tileName) {
|
||||||
final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE);
|
final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE);
|
||||||
final ResolveInfo info = new ResolveInfo();
|
final ResolveInfo info = new ResolveInfo();
|
||||||
|
|||||||
@@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development.bluetooth;
|
||||||
|
|
||||||
|
import static android.bluetooth.BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothA2dp;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothCodecConfig;
|
||||||
|
import android.bluetooth.BluetoothCodecStatus;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import androidx.preference.ListPreference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.development.BluetoothA2dpConfigStore;
|
||||||
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class AbstractBluetoothListPreferenceControllerTest {
|
||||||
|
|
||||||
|
private static final String DEVICE_ADDRESS = "00:11:22:33:44:55";
|
||||||
|
|
||||||
|
private static String DEFAULT_ENTRY;
|
||||||
|
private static final String DEFAULT_ENTRY_VALUE = "1000";
|
||||||
|
|
||||||
|
@Mock private BluetoothA2dp mBluetoothA2dp;
|
||||||
|
@Mock private BluetoothAdapter mBluetoothAdapter;
|
||||||
|
@Mock private PreferenceScreen mScreen;
|
||||||
|
|
||||||
|
private AbstractBluetoothListPreferenceController mController;
|
||||||
|
private ListPreference mPreference;
|
||||||
|
private BluetoothA2dpConfigStore mBluetoothA2dpConfigStore;
|
||||||
|
private BluetoothCodecStatus mCodecStatus;
|
||||||
|
private BluetoothCodecConfig mCodecConfigAAC;
|
||||||
|
private BluetoothCodecConfig mCodecConfigSBC;
|
||||||
|
private BluetoothCodecConfig[] mCodecConfigs = new BluetoothCodecConfig[2];
|
||||||
|
private BluetoothDevice mActiveDevice;
|
||||||
|
private Context mContext;
|
||||||
|
private LifecycleOwner mLifecycleOwner;
|
||||||
|
private Lifecycle mLifecycle;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mLifecycleOwner = () -> mLifecycle;
|
||||||
|
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||||
|
mBluetoothA2dpConfigStore = spy(new BluetoothA2dpConfigStore());
|
||||||
|
mActiveDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(DEVICE_ADDRESS);
|
||||||
|
mController =
|
||||||
|
spy(
|
||||||
|
new AbstractBluetoothListPreferenceControllerImpl(
|
||||||
|
mContext, mLifecycle, mBluetoothA2dpConfigStore));
|
||||||
|
mController.mBluetoothAdapter = mBluetoothAdapter;
|
||||||
|
mPreference = spy(new ListPreference(mContext));
|
||||||
|
|
||||||
|
mCodecConfigAAC =
|
||||||
|
new BluetoothCodecConfig.Builder()
|
||||||
|
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC)
|
||||||
|
.build();
|
||||||
|
mCodecConfigSBC =
|
||||||
|
new BluetoothCodecConfig.Builder()
|
||||||
|
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC)
|
||||||
|
.build();
|
||||||
|
mCodecConfigs[0] = mCodecConfigAAC;
|
||||||
|
mCodecConfigs[1] = mCodecConfigSBC;
|
||||||
|
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.A2DP)))
|
||||||
|
.thenReturn(Arrays.asList(mActiveDevice));
|
||||||
|
|
||||||
|
DEFAULT_ENTRY = mContext.getString(R.string.bluetooth_audio_codec_default_selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifySetupDefaultListPreference() {
|
||||||
|
List<String> entries = new ArrayList<>(1);
|
||||||
|
entries.add(DEFAULT_ENTRY);
|
||||||
|
List<String> entryValues = new ArrayList<>(1);
|
||||||
|
entryValues.add(DEFAULT_ENTRY_VALUE);
|
||||||
|
|
||||||
|
verify(mPreference).setEntries(entries.toArray(new String[entries.size()]));
|
||||||
|
verify(mPreference).setEntryValues(entryValues.toArray(new String[entryValues.size()]));
|
||||||
|
verify(mPreference).setValue(DEFAULT_ENTRY_VALUE);
|
||||||
|
verify(mPreference).setSummary(DEFAULT_ENTRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onPreferenceChange_shouldSetupDefaultListPreference() {
|
||||||
|
mController.onPreferenceChange(mPreference, "" /* new value */);
|
||||||
|
verifySetupDefaultListPreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setupListPreference_wrongSize_shouldSetupDefaultListPreference() {
|
||||||
|
List<String> entries = new ArrayList<>(1);
|
||||||
|
entries.add(DEFAULT_ENTRY);
|
||||||
|
List<String> entryValues = new ArrayList<>(2);
|
||||||
|
entryValues.add(DEFAULT_ENTRY_VALUE);
|
||||||
|
entryValues.add(DEFAULT_ENTRY_VALUE);
|
||||||
|
|
||||||
|
mController.setupListPreference(entries, entryValues, "", "");
|
||||||
|
verifySetupDefaultListPreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setupListPreference_listEmpty_shouldSetupDefaultListPreference() {
|
||||||
|
List<String> entries = new ArrayList<>(1);
|
||||||
|
entries.add(DEFAULT_ENTRY);
|
||||||
|
List<String> entryValues = new ArrayList<>();
|
||||||
|
|
||||||
|
mController.setupListPreference(entries, entryValues, "", "");
|
||||||
|
verifySetupDefaultListPreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBluetoothCodecStatus_errorChecking() {
|
||||||
|
mController.onBluetoothServiceConnected(null);
|
||||||
|
assertThat(mController.getBluetoothCodecStatus()).isNull();
|
||||||
|
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
|
||||||
|
when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(null);
|
||||||
|
assertThat(mController.getBluetoothCodecStatus()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCurrentCodecConfig_errorChecking() {
|
||||||
|
mController.onBluetoothServiceConnected(null);
|
||||||
|
assertThat(mController.getCurrentCodecConfig()).isNull();
|
||||||
|
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(null);
|
||||||
|
assertThat(mController.getCurrentCodecConfig()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCurrentCodecConfig_verifyConfig() {
|
||||||
|
mCodecStatus = new BluetoothCodecStatus.Builder().setCodecConfig(mCodecConfigAAC).build();
|
||||||
|
when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
|
||||||
|
assertThat(mController.getCurrentCodecConfig()).isEqualTo(mCodecConfigAAC);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isHDAudioEnabled_errorChecking() {
|
||||||
|
mController.onBluetoothServiceConnected(null);
|
||||||
|
assertFalse(mController.isHDAudioEnabled());
|
||||||
|
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice))
|
||||||
|
.thenReturn(BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
|
||||||
|
assertFalse(mController.isHDAudioEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isHDAudioEnabled_verifyEnabled() {
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice))
|
||||||
|
.thenReturn(BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
|
||||||
|
assertTrue(mController.isHDAudioEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBluetoothServiceConnected_verifyBluetoothA2dpConfigStore() {
|
||||||
|
mCodecStatus =
|
||||||
|
new BluetoothCodecStatus.Builder()
|
||||||
|
.setCodecConfig(mCodecConfigAAC)
|
||||||
|
.setCodecsSelectableCapabilities(Arrays.asList(mCodecConfigs))
|
||||||
|
.build();
|
||||||
|
when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
|
||||||
|
verify(mBluetoothA2dpConfigStore).setCodecType(mCodecConfigAAC.getExtendedCodecType());
|
||||||
|
verify(mBluetoothA2dpConfigStore).setSampleRate(mCodecConfigAAC.getSampleRate());
|
||||||
|
verify(mBluetoothA2dpConfigStore).setBitsPerSample(mCodecConfigAAC.getBitsPerSample());
|
||||||
|
verify(mBluetoothA2dpConfigStore).setChannelMode(mCodecConfigAAC.getChannelMode());
|
||||||
|
verify(mBluetoothA2dpConfigStore).setCodecPriority(CODEC_PRIORITY_HIGHEST);
|
||||||
|
verify(mBluetoothA2dpConfigStore)
|
||||||
|
.setCodecSpecific1Value(mCodecConfigAAC.getCodecSpecific1());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AbstractBluetoothListPreferenceControllerImpl
|
||||||
|
extends AbstractBluetoothListPreferenceController {
|
||||||
|
|
||||||
|
private AbstractBluetoothListPreferenceControllerImpl(
|
||||||
|
Context context, Lifecycle lifecycle, BluetoothA2dpConfigStore store) {
|
||||||
|
super(context, lifecycle, store);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPreferenceKey() {
|
||||||
|
return "KEY";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeConfigurationValues(String entryValue) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.development.bluetooth;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
|
import static org.mockito.Mockito.eq;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothA2dp;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothCodecConfig;
|
||||||
|
import android.bluetooth.BluetoothCodecStatus;
|
||||||
|
import android.bluetooth.BluetoothCodecType;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import androidx.preference.ListPreference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.development.BluetoothA2dpConfigStore;
|
||||||
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class BluetoothCodecListPreferenceControllerTest {
|
||||||
|
|
||||||
|
private static final String DEVICE_ADDRESS = "00:11:22:33:44:55";
|
||||||
|
|
||||||
|
@Mock private BluetoothA2dp mBluetoothA2dp;
|
||||||
|
@Mock private BluetoothAdapter mBluetoothAdapter;
|
||||||
|
@Mock private PreferenceScreen mScreen;
|
||||||
|
@Mock private AbstractBluetoothPreferenceController.Callback mCallback;
|
||||||
|
|
||||||
|
private BluetoothCodecListPreferenceController mController;
|
||||||
|
private ListPreference mPreference;
|
||||||
|
private BluetoothA2dpConfigStore mBluetoothA2dpConfigStore;
|
||||||
|
private BluetoothCodecStatus mCodecStatus;
|
||||||
|
private BluetoothCodecType mCodecTypeAAC;
|
||||||
|
private BluetoothCodecType mCodecTypeSBC;
|
||||||
|
private BluetoothCodecType mCodecTypeAPTX;
|
||||||
|
private BluetoothCodecType mCodecTypeLDAC;
|
||||||
|
private BluetoothCodecType mCodecTypeOPUS;
|
||||||
|
private List<BluetoothCodecType> mCodecTypes;
|
||||||
|
|
||||||
|
private BluetoothCodecConfig mCodecConfigAAC;
|
||||||
|
private BluetoothCodecConfig mCodecConfigSBC;
|
||||||
|
private BluetoothCodecConfig mCodecConfigAPTX;
|
||||||
|
private BluetoothCodecConfig mCodecConfigAPTXHD;
|
||||||
|
private BluetoothCodecConfig mCodecConfigLDAC;
|
||||||
|
private BluetoothCodecConfig mCodecConfigOPUS;
|
||||||
|
private List<BluetoothCodecConfig> mCodecConfigs;
|
||||||
|
private BluetoothDevice mActiveDevice;
|
||||||
|
private Context mContext;
|
||||||
|
private LifecycleOwner mLifecycleOwner;
|
||||||
|
private Lifecycle mLifecycle;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mLifecycleOwner = () -> mLifecycle;
|
||||||
|
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||||
|
mBluetoothA2dpConfigStore = spy(new BluetoothA2dpConfigStore());
|
||||||
|
mActiveDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(DEVICE_ADDRESS);
|
||||||
|
mController =
|
||||||
|
new BluetoothCodecListPreferenceController(
|
||||||
|
mContext, mLifecycle, mBluetoothA2dpConfigStore, mCallback);
|
||||||
|
mController.mBluetoothAdapter = mBluetoothAdapter;
|
||||||
|
mPreference = new ListPreference(mContext);
|
||||||
|
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
|
mCodecTypeAAC =
|
||||||
|
BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC);
|
||||||
|
mCodecTypeSBC =
|
||||||
|
BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC);
|
||||||
|
mCodecTypeAPTX =
|
||||||
|
BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX);
|
||||||
|
mCodecTypeLDAC =
|
||||||
|
BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC);
|
||||||
|
mCodecTypeOPUS =
|
||||||
|
BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS);
|
||||||
|
|
||||||
|
mCodecTypes = new ArrayList<>();
|
||||||
|
mCodecTypes.addAll(
|
||||||
|
Arrays.asList(
|
||||||
|
mCodecTypeSBC,
|
||||||
|
mCodecTypeAAC,
|
||||||
|
mCodecTypeAPTX,
|
||||||
|
mCodecTypeLDAC,
|
||||||
|
mCodecTypeOPUS));
|
||||||
|
|
||||||
|
mCodecConfigSBC =
|
||||||
|
new BluetoothCodecConfig.Builder()
|
||||||
|
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC)
|
||||||
|
.setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)
|
||||||
|
.setSampleRate(
|
||||||
|
BluetoothCodecConfig.SAMPLE_RATE_96000
|
||||||
|
| BluetoothCodecConfig.SAMPLE_RATE_176400)
|
||||||
|
.setBitsPerSample(BluetoothCodecConfig.BITS_PER_SAMPLE_32)
|
||||||
|
.setChannelMode(
|
||||||
|
BluetoothCodecConfig.CHANNEL_MODE_MONO
|
||||||
|
| BluetoothCodecConfig.CHANNEL_MODE_STEREO)
|
||||||
|
.build();
|
||||||
|
mCodecConfigAAC =
|
||||||
|
new BluetoothCodecConfig.Builder()
|
||||||
|
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC)
|
||||||
|
.setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST)
|
||||||
|
.setSampleRate(
|
||||||
|
BluetoothCodecConfig.SAMPLE_RATE_48000
|
||||||
|
| BluetoothCodecConfig.SAMPLE_RATE_88200)
|
||||||
|
.setBitsPerSample(
|
||||||
|
BluetoothCodecConfig.BITS_PER_SAMPLE_16
|
||||||
|
| BluetoothCodecConfig.BITS_PER_SAMPLE_24)
|
||||||
|
.setChannelMode(BluetoothCodecConfig.CHANNEL_MODE_STEREO)
|
||||||
|
.build();
|
||||||
|
mCodecConfigAPTX =
|
||||||
|
new BluetoothCodecConfig.Builder()
|
||||||
|
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX)
|
||||||
|
.build();
|
||||||
|
mCodecConfigAPTXHD =
|
||||||
|
new BluetoothCodecConfig.Builder()
|
||||||
|
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD)
|
||||||
|
.build();
|
||||||
|
mCodecConfigLDAC =
|
||||||
|
new BluetoothCodecConfig.Builder()
|
||||||
|
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC)
|
||||||
|
.build();
|
||||||
|
mCodecConfigOPUS =
|
||||||
|
new BluetoothCodecConfig.Builder()
|
||||||
|
.setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
mCodecConfigs = new ArrayList<>();
|
||||||
|
mCodecConfigs.addAll(
|
||||||
|
Arrays.asList(
|
||||||
|
mCodecConfigOPUS,
|
||||||
|
mCodecConfigAAC,
|
||||||
|
mCodecConfigSBC,
|
||||||
|
mCodecConfigAPTX,
|
||||||
|
mCodecConfigAPTXHD,
|
||||||
|
mCodecConfigLDAC));
|
||||||
|
|
||||||
|
when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.A2DP)))
|
||||||
|
.thenReturn(Arrays.asList(mActiveDevice));
|
||||||
|
when(mBluetoothA2dp.getSupportedCodecTypes()).thenReturn(mCodecTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeConfigurationValues_selectDefault() {
|
||||||
|
mCodecStatus =
|
||||||
|
new BluetoothCodecStatus.Builder()
|
||||||
|
.setCodecConfig(mCodecConfigSBC)
|
||||||
|
.setCodecsSelectableCapabilities(mCodecConfigs)
|
||||||
|
.build();
|
||||||
|
when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
|
||||||
|
when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice))
|
||||||
|
.thenReturn(BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
|
||||||
|
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
|
||||||
|
mController.writeConfigurationValues(String.valueOf(mController.DEFAULT_VALUE_INT));
|
||||||
|
verify(mBluetoothA2dpConfigStore, times(2)).setCodecType(mCodecTypeSBC);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeConfigurationValues_checkCodec() {
|
||||||
|
mCodecStatus =
|
||||||
|
new BluetoothCodecStatus.Builder()
|
||||||
|
.setCodecConfig(mCodecConfigSBC)
|
||||||
|
.setCodecsSelectableCapabilities(mCodecConfigs)
|
||||||
|
.build();
|
||||||
|
when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
|
||||||
|
mController.writeConfigurationValues(String.valueOf(mCodecTypeSBC.getCodecId()));
|
||||||
|
verify(mBluetoothA2dpConfigStore, atLeastOnce()).setCodecType(mCodecTypeSBC);
|
||||||
|
|
||||||
|
mController.writeConfigurationValues(String.valueOf(mCodecTypeAAC.getCodecId()));
|
||||||
|
verify(mBluetoothA2dpConfigStore).setCodecType(mCodecTypeAAC);
|
||||||
|
|
||||||
|
mController.writeConfigurationValues(String.valueOf(mCodecTypeAPTX.getCodecId()));
|
||||||
|
verify(mBluetoothA2dpConfigStore).setCodecType(mCodecTypeAPTX);
|
||||||
|
|
||||||
|
mController.writeConfigurationValues(String.valueOf(mCodecTypeLDAC.getCodecId()));
|
||||||
|
verify(mBluetoothA2dpConfigStore).setCodecType(mCodecTypeLDAC);
|
||||||
|
|
||||||
|
mController.writeConfigurationValues(String.valueOf(mCodecTypeOPUS.getCodecId()));
|
||||||
|
verify(mBluetoothA2dpConfigStore).setCodecType(mCodecTypeOPUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeConfigurationValues_chooseHighestConfig() {
|
||||||
|
mCodecStatus =
|
||||||
|
new BluetoothCodecStatus.Builder()
|
||||||
|
.setCodecConfig(mCodecConfigSBC)
|
||||||
|
.setCodecsSelectableCapabilities((mCodecConfigs))
|
||||||
|
.build();
|
||||||
|
when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
mController.writeConfigurationValues(String.valueOf(mCodecTypeAAC.getCodecId()));
|
||||||
|
|
||||||
|
verify(mBluetoothA2dpConfigStore, atLeastOnce())
|
||||||
|
.setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST);
|
||||||
|
verify(mBluetoothA2dpConfigStore, atLeastOnce())
|
||||||
|
.setSampleRate(BluetoothCodecConfig.SAMPLE_RATE_88200);
|
||||||
|
verify(mBluetoothA2dpConfigStore, atLeastOnce())
|
||||||
|
.setBitsPerSample(BluetoothCodecConfig.BITS_PER_SAMPLE_24);
|
||||||
|
verify(mBluetoothA2dpConfigStore, atLeastOnce())
|
||||||
|
.setChannelMode(BluetoothCodecConfig.CHANNEL_MODE_STEREO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onPreferenceChange_notifyPreference() {
|
||||||
|
assertFalse(
|
||||||
|
mController.onPreferenceChange(
|
||||||
|
mPreference, String.valueOf(mCodecTypeAAC.getCodecId())));
|
||||||
|
|
||||||
|
mController.onBluetoothServiceConnected(mBluetoothA2dp);
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
mController.onPreferenceChange(
|
||||||
|
mPreference, String.valueOf(mCodecTypeAAC.getCodecId())));
|
||||||
|
|
||||||
|
verify(mCallback).onBluetoothCodecChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onHDAudioEnabled_setsPreferenceEnabled() {
|
||||||
|
mController.onHDAudioEnabled(/* enabled= */ true);
|
||||||
|
assertThat(mPreference.isEnabled()).isTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,7 +58,6 @@ import com.android.settings.testutils.FakeFeatureFactory;
|
|||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
|
||||||
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;
|
||||||
@@ -203,7 +202,6 @@ public class AppLocalePickerActivityTest {
|
|||||||
assertThat(controller.get().isFinishing()).isTrue();
|
assertThat(controller.get().isFinishing()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("b/313604701")
|
|
||||||
@Test
|
@Test
|
||||||
public void onLocaleSelected_getLocaleNotNull_getLanguageTag() {
|
public void onLocaleSelected_getLocaleNotNull_getLanguageTag() {
|
||||||
ActivityController<TestAppLocalePickerActivity> controller =
|
ActivityController<TestAppLocalePickerActivity> controller =
|
||||||
@@ -216,7 +214,10 @@ public class AppLocalePickerActivityTest {
|
|||||||
AppLocalePickerActivity mActivity = controller.get();
|
AppLocalePickerActivity mActivity = controller.get();
|
||||||
mActivity.onLocaleSelected(mLocaleInfo);
|
mActivity.onLocaleSelected(mLocaleInfo);
|
||||||
|
|
||||||
verify(mLocaleInfo, times(2)).getLocale();
|
// 1st for getLocale()!= null
|
||||||
|
// 2nd for setAppDefaultLocale(getLocale())
|
||||||
|
// 3rd for broadcastAppLocaleChange()
|
||||||
|
verify(mLocaleInfo, times(3)).getLocale();
|
||||||
assertThat(mLocaleInfo.getLocale().toLanguageTag()).isEqualTo("en-US");
|
assertThat(mLocaleInfo.getLocale().toLanguageTag()).isEqualTo("en-US");
|
||||||
assertThat(controller.get().isFinishing()).isTrue();
|
assertThat(controller.get().isFinishing()).isTrue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,9 @@ import android.content.Context
|
|||||||
import android.platform.test.flag.junit.SetFlagsRule
|
import android.platform.test.flag.junit.SetFlagsRule
|
||||||
import android.telephony.SubscriptionInfo
|
import android.telephony.SubscriptionInfo
|
||||||
import android.telephony.SubscriptionManager
|
import android.telephony.SubscriptionManager
|
||||||
import android.telephony.TelephonyCallback
|
|
||||||
import android.telephony.TelephonyManager
|
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.android.internal.telephony.flags.Flags
|
import com.android.internal.telephony.flags.Flags
|
||||||
import com.android.settings.network.telephony.CallStateFlowTest
|
|
||||||
import com.android.settingslib.spa.testutils.toListWithTimeout
|
import com.android.settingslib.spa.testutils.toListWithTimeout
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
@@ -42,7 +39,6 @@ import org.mockito.kotlin.doAnswer
|
|||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.spy
|
import org.mockito.kotlin.spy
|
||||||
import org.mockito.kotlin.stub
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class SubscriptionInfoListViewModelTest {
|
class SubscriptionInfoListViewModelTest {
|
||||||
@@ -62,8 +58,7 @@ class SubscriptionInfoListViewModelTest {
|
|||||||
on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager
|
on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
private val subscriptionInfoListViewModel: SubscriptionInfoListViewModel =
|
private fun createViewModel() = SubscriptionInfoListViewModel(context as Application)
|
||||||
SubscriptionInfoListViewModel(context as Application);
|
|
||||||
|
|
||||||
private var activeSubscriptionInfoList: List<SubscriptionInfo>? = null
|
private var activeSubscriptionInfoList: List<SubscriptionInfo>? = null
|
||||||
|
|
||||||
@@ -72,7 +67,7 @@ class SubscriptionInfoListViewModelTest {
|
|||||||
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2)
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2)
|
||||||
|
|
||||||
val listDeferred = async {
|
val listDeferred = async {
|
||||||
subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout()
|
createViewModel().subscriptionInfoListFlow.toListWithTimeout()
|
||||||
}
|
}
|
||||||
delay(100)
|
delay(100)
|
||||||
subInfoListener?.onSubscriptionsChanged()
|
subInfoListener?.onSubscriptionsChanged()
|
||||||
@@ -83,49 +78,44 @@ class SubscriptionInfoListViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun onSubscriptionsChanged_hasProvisioning_filterProvisioning() = runBlocking {
|
fun onSubscriptionsChanged_hasProvisioning_filterProvisioning() = runBlocking {
|
||||||
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_3)
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_3)
|
||||||
val expectation = listOf(SUB_INFO_1, SUB_INFO_2)
|
|
||||||
|
|
||||||
val listDeferred = async {
|
val listDeferred = async {
|
||||||
subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout()
|
createViewModel().subscriptionInfoListFlow.toListWithTimeout()
|
||||||
}
|
}
|
||||||
delay(100)
|
delay(100)
|
||||||
subInfoListener?.onSubscriptionsChanged()
|
subInfoListener?.onSubscriptionsChanged()
|
||||||
|
|
||||||
assertThat(listDeferred.await()).contains(expectation)
|
assertThat(listDeferred.await()).contains(listOf(SUB_INFO_1, SUB_INFO_2))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onSubscriptionsChanged_flagOffHasNonTerrestrialNetwork_filterNonTerrestrialNetwork() =
|
fun onSubscriptionsChanged_flagOffHasNonTerrestrialNetwork_filterNonTerrestrialNetwork() =
|
||||||
runBlocking {
|
runBlocking {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
|
mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
|
||||||
|
|
||||||
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)
|
||||||
val expectation = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)
|
|
||||||
|
|
||||||
val listDeferred = async {
|
val listDeferred = async {
|
||||||
subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout()
|
createViewModel().subscriptionInfoListFlow.toListWithTimeout()
|
||||||
}
|
}
|
||||||
delay(100)
|
delay(100)
|
||||||
subInfoListener?.onSubscriptionsChanged()
|
subInfoListener?.onSubscriptionsChanged()
|
||||||
|
|
||||||
assertThat(listDeferred.await()).contains(expectation)
|
assertThat(listDeferred.await()).contains(listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onSubscriptionsChanged_flagOnHasNonTerrestrialNetwork_filterNonTerrestrialNetwork() =
|
fun onSubscriptionsChanged_flagOnHasNonTerrestrialNetwork_filterNonTerrestrialNetwork() =
|
||||||
runBlocking {
|
runBlocking {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
|
mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
|
||||||
|
|
||||||
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)
|
activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)
|
||||||
val expectation = listOf(SUB_INFO_1, SUB_INFO_2)
|
|
||||||
|
|
||||||
val listDeferred = async {
|
val listDeferred = async {
|
||||||
subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout()
|
createViewModel().subscriptionInfoListFlow.toListWithTimeout()
|
||||||
}
|
}
|
||||||
delay(100)
|
delay(100)
|
||||||
subInfoListener?.onSubscriptionsChanged()
|
subInfoListener?.onSubscriptionsChanged()
|
||||||
|
|
||||||
assertThat(listDeferred.await()).contains(expectation)
|
assertThat(listDeferred.await()).contains(listOf(SUB_INFO_1, SUB_INFO_2))
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
|||||||
@@ -208,6 +208,23 @@ public class PreferredShortcutsTest {
|
|||||||
assertThat(savedPreferredShortcut).isEqualTo(UserShortcutType.HARDWARE);
|
assertThat(savedPreferredShortcut).isEqualTo(UserShortcutType.HARDWARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void retrieveUserShortcutTypeWithoutDefault_noUserPreferredShortcuts_returnSoftwareShortcut() {
|
||||||
|
String target = COMPONENT_NAME_1.flattenToString();
|
||||||
|
|
||||||
|
assertThat(PreferredShortcuts.retrieveUserShortcutType(mContext, target))
|
||||||
|
.isEqualTo(UserShortcutType.SOFTWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void retrieveUserShortcutTypeWithDefaultAsDefault_noUserPreferredShortcuts_returnSpecifiedDefault() {
|
||||||
|
String target = COMPONENT_NAME_1.flattenToString();
|
||||||
|
|
||||||
|
assertThat(PreferredShortcuts.retrieveUserShortcutType(mContext, target,
|
||||||
|
UserShortcutType.HARDWARE))
|
||||||
|
.isEqualTo(UserShortcutType.HARDWARE);
|
||||||
|
}
|
||||||
|
|
||||||
private static void clearShortcuts() {
|
private static void clearShortcuts() {
|
||||||
Settings.Secure.putString(sContentResolver,
|
Settings.Secure.putString(sContentResolver,
|
||||||
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "");
|
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "");
|
||||||
|
|||||||
Reference in New Issue
Block a user