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

Commit 7764a3e5 authored by Haijie Hong's avatar Haijie Hong
Browse files

Fix coroutine scope expired and UI animation issue

BUG: 375365790
BUG: 375146578
BUG: 375304695
BUG: 375544752
Test: atest BluetoothDeviceDetailsViewModelTest
Flag: com.android.settings.flags.enable_bluetooth_device_details_polish
Change-Id: Ib3bc6699f256288b6c4995b78cc25a16f1af0792
parent ab9f9780
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -421,11 +421,13 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
    protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
        List<String> invisibleProfiles = List.of();
        if (Flags.enableBluetoothDeviceDetailsPolish()) {
            if (mFormatter == null) {
                mFormatter =
                        FeatureFactory.getFeatureFactory()
                                .getBluetoothFeatureProvider()
                                .getDeviceDetailsFragmentFormatter(
                                        requireContext(), this, mBluetoothAdapter, mCachedDevice);
            }
            invisibleProfiles =
                    mFormatter.getInvisibleBluetoothProfiles(
                            FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
+7 −9
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.media.Spatializer;
import android.net.Uri;

import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleCoroutineScope;
import androidx.preference.Preference;

import com.android.settings.SettingsPreferenceFragment;
@@ -34,12 +33,12 @@ import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository;

import kotlinx.coroutines.CoroutineScope;

import java.util.List;
import java.util.Set;

/**
 * Provider for bluetooth related features.
 */
/** Provider for bluetooth related features. */
public interface BluetoothFeatureProvider {

    /**
@@ -90,22 +89,21 @@ public interface BluetoothFeatureProvider {
     * @param bluetoothDevice the bluetooth device
     * @return the profiles which should be hidden
     */
    Set<String> getInvisibleProfilePreferenceKeys(
            Context context, BluetoothDevice bluetoothDevice);
    Set<String> getInvisibleProfilePreferenceKeys(Context context, BluetoothDevice bluetoothDevice);

    /** Gets DeviceSettingRepository. */
    @NonNull
    DeviceSettingRepository getDeviceSettingRepository(
            @NonNull Context context,
            @NonNull BluetoothAdapter bluetoothAdapter,
            @NonNull LifecycleCoroutineScope scope);
            @NonNull CoroutineScope scope);

    /** Gets spatial audio interactor. */
    @NonNull
    SpatialAudioInteractor getSpatialAudioInteractor(
            @NonNull Context context,
            @NonNull AudioManager audioManager,
            @NonNull LifecycleCoroutineScope scope);
            @NonNull CoroutineScope scope);

    /** Gets device details fragment layout formatter. */
    @NonNull
+4 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Context
import android.media.AudioManager
import android.media.Spatializer
import android.net.Uri
import android.util.Log
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.preference.Preference
import com.android.settings.SettingsPreferenceFragment
@@ -37,6 +38,7 @@ import com.android.settingslib.media.data.repository.SpatializerRepositoryImpl
import com.android.settingslib.media.domain.interactor.SpatializerInteractor
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableSet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

/** Impl of [BluetoothFeatureProvider] */
@@ -76,14 +78,14 @@ open class BluetoothFeatureProviderImpl : BluetoothFeatureProvider {
    override fun getDeviceSettingRepository(
        context: Context,
        bluetoothAdapter: BluetoothAdapter,
        scope: LifecycleCoroutineScope
        scope: CoroutineScope
    ): DeviceSettingRepository =
        DeviceSettingRepositoryImpl(context, bluetoothAdapter, scope, Dispatchers.IO)

    override fun getSpatialAudioInteractor(
        context: Context,
        audioManager: AudioManager,
        scope: LifecycleCoroutineScope
        scope: CoroutineScope,
    ): SpatialAudioInteractor {
        return SpatialAudioInteractorImpl(
            context, audioManager,
+1 −1
Original line number Diff line number Diff line
@@ -147,7 +147,7 @@ class SpatialAudioInteractorImpl(
    }

    companion object {
        private const val TAG = "SpatialAudioInteractorImpl"
        private const val TAG = "SpatialAudioInteractor"
        private const val INDEX_SPATIAL_AUDIO_OFF = 0
        private const val INDEX_SPATIAL_AUDIO_ON = 1
        private const val INDEX_HEAD_TRACKING_ENABLED = 2
+7 −23
Original line number Diff line number Diff line
@@ -19,11 +19,10 @@ package com.android.settings.bluetooth.ui.view
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
import android.media.AudioManager
import android.os.Bundle
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
@@ -33,14 +32,12 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import com.android.settings.R
import com.android.settings.SettingsPreferenceFragment
@@ -52,7 +49,6 @@ import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.bluetooth.ui.view.DeviceDetailsMoreSettingsFragment.Companion.KEY_DEVICE_ADDRESS
import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
import com.android.settings.core.SubSettingLauncher
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settings.spa.preference.ComposePreference
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
@@ -97,29 +93,17 @@ interface DeviceDetailsFragmentFormatter {
class DeviceDetailsFragmentFormatterImpl(
    private val context: Context,
    private val fragment: SettingsPreferenceFragment,
    bluetoothAdapter: BluetoothAdapter,
    private val bluetoothAdapter: BluetoothAdapter,
    private val cachedDevice: CachedBluetoothDevice,
    private val backgroundCoroutineContext: CoroutineContext,
) : DeviceDetailsFragmentFormatter {
    private val repository =
        featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
            fragment.requireActivity().application,
            bluetoothAdapter,
            fragment.lifecycleScope,
        )
    private val spatialAudioInteractor =
        featureFactory.bluetoothFeatureProvider.getSpatialAudioInteractor(
            fragment.requireActivity().application,
            context.getSystemService(AudioManager::class.java),
            fragment.lifecycleScope,
        )

    private val viewModel: BluetoothDeviceDetailsViewModel =
        ViewModelProvider(
                fragment,
                BluetoothDeviceDetailsViewModel.Factory(
                    fragment.requireActivity().application,
                    repository,
                    spatialAudioInteractor,
                    bluetoothAdapter,
                    cachedDevice,
                    backgroundCoroutineContext,
                ),
@@ -224,8 +208,8 @@ class DeviceDetailsFragmentFormatterImpl(
        val settings = contents
        AnimatedVisibility(
            visible = settings.isNotEmpty(),
            enter = expandVertically(expandFrom = Alignment.Top),
            exit = shrinkVertically(shrinkTowards = Alignment.Top),
            enter = fadeIn(),
            exit = fadeOut(),
        ) {
            Box {
                Box(
Loading