Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82648955 authored by Haijie Hong's avatar Haijie Hong
Browse files

Implement Spatial audio toggle domain layer

BUG: 343317785
Test: atest SpatialAudioInteractorTest
Flag: com.android.settings.flags.enable_bluetooth_device_details_polish
Change-Id: Id3f2254900c3cd8745c5fab522484891ad1406da
parent 5641f269
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.net.Uri;
import android.provider.DeviceConfig;
@@ -41,9 +43,12 @@ import com.android.settingslib.flags.Flags;
import com.android.settingslib.widget.AdaptiveIcon;
import com.android.settingslib.widget.AdaptiveOutlineDrawable;

import com.google.common.collect.ImmutableSet;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@@ -57,6 +62,9 @@ public class BluetoothUtils {
    public static final String BT_ADVANCED_HEADER_ENABLED = "bt_advanced_header_enabled";
    private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
    private static final String KEY_HEARABLE_CONTROL_SLICE = "HEARABLE_CONTROL_SLICE_WITH_WIDTH";
    private static final Set<Integer> SA_PROFILES =
            ImmutableSet.of(
                    BluetoothProfile.A2DP, BluetoothProfile.LE_AUDIO, BluetoothProfile.HEARING_AID);

    private static ErrorListener sErrorListener;

@@ -895,4 +903,62 @@ public class BluetoothUtils {
        }
        return null;
    }

    /**
     * Gets {@link AudioDeviceAttributes} of bluetooth device for spatial audio. Returns null if
     * it's not an audio device(no A2DP, LE Audio and Hearing Aid profile).
     */
    @Nullable
    public static AudioDeviceAttributes getAudioDeviceAttributesForSpatialAudio(
            CachedBluetoothDevice cachedDevice,
            @AudioManager.AudioDeviceCategory int audioDeviceCategory) {
        AudioDeviceAttributes saDevice = null;
        for (LocalBluetoothProfile profile : cachedDevice.getProfiles()) {
            // pick first enabled profile that is compatible with spatial audio
            if (SA_PROFILES.contains(profile.getProfileId())
                    && profile.isEnabled(cachedDevice.getDevice())) {
                switch (profile.getProfileId()) {
                    case BluetoothProfile.A2DP:
                        saDevice =
                                new AudioDeviceAttributes(
                                        AudioDeviceAttributes.ROLE_OUTPUT,
                                        AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
                                        cachedDevice.getAddress());
                        break;
                    case BluetoothProfile.LE_AUDIO:
                        if (audioDeviceCategory
                                == AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER) {
                            saDevice =
                                    new AudioDeviceAttributes(
                                            AudioDeviceAttributes.ROLE_OUTPUT,
                                            AudioDeviceInfo.TYPE_BLE_SPEAKER,
                                            cachedDevice.getAddress());
                        } else {
                            saDevice =
                                    new AudioDeviceAttributes(
                                            AudioDeviceAttributes.ROLE_OUTPUT,
                                            AudioDeviceInfo.TYPE_BLE_HEADSET,
                                            cachedDevice.getAddress());
                        }

                        break;
                    case BluetoothProfile.HEARING_AID:
                        saDevice =
                                new AudioDeviceAttributes(
                                        AudioDeviceAttributes.ROLE_OUTPUT,
                                        AudioDeviceInfo.TYPE_HEARING_AID,
                                        cachedDevice.getAddress());
                        break;
                    default:
                        Log.i(
                                TAG,
                                "unrecognized profile for spatial audio: "
                                        + profile.getProfileId());
                        break;
                }
                break;
            }
        }
        return saDevice;
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -108,6 +108,12 @@ public @interface DeviceSettingId {
    /** Device setting ID for device details footer. */
    int DEVICE_SETTING_ID_DEVICE_DETAILS_FOOTER = 19;

    /** Device setting ID for spatial audio group. */
    int DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE = 20;

    /** Device setting ID for "More Settings" page. */
    int DEVICE_SETTING_ID_MORE_SETTINGS = 21;

    /** Device setting ID for ANC. */
    int DEVICE_SETTING_ID_ANC = 1001;
}
+4 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.settingslib.bluetooth.devicesettings.MultiTogglePreference
import com.android.settingslib.bluetooth.devicesettings.ToggleInfo
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
@@ -117,7 +118,7 @@ class DeviceSettingRepositoryImpl(
                    id = settingId,
                    title = pref.title,
                    summary = pref.summary,
                    icon = pref.icon,
                    icon = pref.icon?.let { DeviceSettingIcon.BitmapIcon(it) },
                    isAllowedChangingState = pref.isAllowedChangingState,
                    intent = pref.intent,
                    switchState =
@@ -153,5 +154,6 @@ class DeviceSettingRepositoryImpl(
            else -> DeviceSettingModel.Unknown(cachedDevice, settingId)
        }

    private fun ToggleInfo.toModel(): ToggleModel = ToggleModel(label, icon)
    private fun ToggleInfo.toModel(): ToggleModel =
        ToggleModel(label, DeviceSettingIcon.BitmapIcon(icon))
}
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ sealed interface DeviceSettingConfigItemModel {
    /** A built-in item in Settings. */
    data class BuiltinItem(
        @DeviceSettingId override val settingId: Int,
        val preferenceKey: String
        val preferenceKey: String?
    ) : DeviceSettingConfigItemModel

    /** A remote item provided by other apps. */
+11 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth.devicesettings.shared.model

import android.content.Intent
import android.graphics.Bitmap
import androidx.annotation.DrawableRes
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId

@@ -32,7 +33,7 @@ sealed interface DeviceSettingModel {
        @DeviceSettingId override val id: Int,
        val title: String,
        val summary: String? = null,
        val icon: Bitmap? = null,
        val icon: DeviceSettingIcon? = null,
        val intent: Intent? = null,
        val switchState: DeviceSettingStateModel.ActionSwitchPreferenceState? = null,
        val isAllowedChangingState: Boolean = true,
@@ -59,4 +60,12 @@ sealed interface DeviceSettingModel {
}

/** Models a toggle in [DeviceSettingModel.MultiTogglePreference]. */
data class ToggleModel(val label: String, val icon: Bitmap)
data class ToggleModel(val label: String, val icon: DeviceSettingIcon)

/** Models an icon in device settings. */
sealed interface DeviceSettingIcon {

    data class BitmapIcon(val bitmap: Bitmap) : DeviceSettingIcon

    data class ResourceIcon(@DrawableRes val resId: Int) : DeviceSettingIcon
}
Loading