diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java index 60a8a1329f7..6fd6f18bc24 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java @@ -16,7 +16,6 @@ package com.android.settings.connecteddevice.audiosharing; -import android.app.settings.SettingsEnums; import android.content.Context; import android.util.Log; @@ -30,6 +29,7 @@ import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.utils.ThreadUtils; public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater implements Preference.OnPreferenceClickListener { @@ -73,7 +73,9 @@ public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater @Override public boolean onPreferenceClick(Preference preference) { mMetricsFeatureProvider.logClickedPreference(preference, mMetricsCategory); - mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUDIO_SHARING_DEVICE_CLICK); + var unused = + ThreadUtils.postOnBackgroundThread( + () -> mDevicePreferenceCallback.onDeviceClick(preference)); return true; } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java index 8b4c7f267bb..db2c7b21b1b 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.connecteddevice.audiosharing; +import static com.android.settingslib.Utils.isAudioModeOngoingCall; import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE; import android.app.settings.SettingsEnums; @@ -39,7 +40,9 @@ import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; +import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.BluetoothDeviceUpdater; import com.android.settings.bluetooth.Utils; import com.android.settings.connecteddevice.DevicePreferenceCallback; @@ -91,6 +94,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro @Nullable private DashboardFragment mFragment; @Nullable private AudioSharingDialogHandler mDialogHandler; private AtomicBoolean mIntentHandled = new AtomicBoolean(false); + private AtomicBoolean mIsAudioModeOngoingCall = new AtomicBoolean(false); @VisibleForTesting BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = @@ -201,51 +205,57 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro @Override public void onStart(@NonNull LifecycleOwner owner) { - if (!isAvailable()) { - Log.d(TAG, "Skip onStart(), feature is not supported."); - return; - } - if (!AudioSharingUtils.isAudioSharingProfileReady(mProfileManager) - && mProfileManager != null) { - Log.d(TAG, "Register profile service listener"); - mProfileManager.addServiceListener(this); - } - if (mEventManager == null - || mAssistant == null - || mDialogHandler == null - || mBluetoothDeviceUpdater == null) { - Log.d(TAG, "Skip onStart(), profile is not ready."); - return; - } - Log.d(TAG, "onStart() Register callbacks."); - mEventManager.registerCallback(this); - mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback); - mDialogHandler.registerCallbacks(mExecutor); - mBluetoothDeviceUpdater.registerCallback(); - mBluetoothDeviceUpdater.refreshPreference(); + var unused = ThreadUtils.postOnBackgroundThread(() -> { + if (!isAvailable()) { + Log.d(TAG, "Skip onStart(), feature is not supported."); + return; + } + if (!AudioSharingUtils.isAudioSharingProfileReady(mProfileManager) + && mProfileManager != null) { + Log.d(TAG, "Register profile service listener"); + mProfileManager.addServiceListener(this); + } + if (mEventManager == null + || mAssistant == null + || mDialogHandler == null + || mBluetoothDeviceUpdater == null) { + Log.d(TAG, "Skip onStart(), profile is not ready."); + return; + } + Log.d(TAG, "onStart() Register callbacks."); + mEventManager.registerCallback(this); + mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback); + mDialogHandler.registerCallbacks(mExecutor); + mBluetoothDeviceUpdater.registerCallback(); + mBluetoothDeviceUpdater.refreshPreference(); + mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext)); + updateTitle(); + }); } @Override public void onStop(@NonNull LifecycleOwner owner) { - if (!isAvailable()) { - Log.d(TAG, "Skip onStop(), feature is not supported."); - return; - } - if (mProfileManager != null) { - mProfileManager.removeServiceListener(this); - } - if (mEventManager == null - || mAssistant == null - || mDialogHandler == null - || mBluetoothDeviceUpdater == null) { - Log.d(TAG, "Skip onStop(), profile is not ready."); - return; - } - Log.d(TAG, "onStop() Unregister callbacks."); - mEventManager.unregisterCallback(this); - mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback); - mDialogHandler.unregisterCallbacks(); - mBluetoothDeviceUpdater.unregisterCallback(); + var unused = ThreadUtils.postOnBackgroundThread(() -> { + if (!isAvailable()) { + Log.d(TAG, "Skip onStop(), feature is not supported."); + return; + } + if (mProfileManager != null) { + mProfileManager.removeServiceListener(this); + } + if (mEventManager == null + || mAssistant == null + || mDialogHandler == null + || mBluetoothDeviceUpdater == null) { + Log.d(TAG, "Skip onStop(), profile is not ready."); + return; + } + Log.d(TAG, "onStop() Unregister callbacks."); + mEventManager.unregisterCallback(this); + mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback); + mDialogHandler.unregisterCallbacks(); + mBluetoothDeviceUpdater.unregisterCallback(); + }); } @Override @@ -367,6 +377,25 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro handleOnProfileStateChanged(cachedDevice, bluetoothProfile); } + @Override + public void onAudioModeChanged() { + mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext)); + updateTitle(); + } + + @Override + public void onDeviceClick(@NonNull Preference preference) { + boolean isCallMode = mIsAudioModeOngoingCall.get(); + if (isCallMode) { + Log.d(TAG, "onDeviceClick, set active in call mode"); + CachedBluetoothDevice cachedDevice = + ((BluetoothDevicePreference) preference).getBluetoothDevice(); + cachedDevice.setActive(); + } + mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUDIO_SHARING_DEVICE_CLICK, + isCallMode); + } + /** * Initialize the controller. * @@ -499,4 +528,22 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro mDialogHandler.handleDeviceConnected(cachedDevice, /* userTriggered= */ true); } } + + private void updateTitle() { + if (mPreferenceGroup == null) return; + int titleResId; + if (mIsAudioModeOngoingCall.get()) { + // in phone call + titleResId = R.string.connected_device_call_device_title; + } else { + // without phone call + titleResId = R.string.audio_sharing_device_group_title; + } + AudioSharingUtils.postOnMainThread(mContext, + () -> { + if (mPreferenceGroup != null) { + mPreferenceGroup.setTitle(titleResId); + } + }); + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java index 879c6a4d0ab..11e31b6fa03 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java @@ -28,7 +28,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; -import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastReceiveState; @@ -271,8 +270,9 @@ public class AudioSharingBluetoothDeviceUpdaterTest { public void onPreferenceClick_logClick() { Preference preference = new Preference(mContext); mDeviceUpdater.onPreferenceClick(preference); - verify(mFeatureFactory.metricsFeatureProvider) - .action(mContext, SettingsEnums.ACTION_AUDIO_SHARING_DEVICE_CLICK); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDevicePreferenceCallback).onDeviceClick(preference); } private void setupPreferenceMapWithDevice() { diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java index 03f13037d62..61bc8aaa055 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -44,10 +45,14 @@ import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; import android.content.Context; import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; import android.os.Bundle; import android.os.Looper; import android.platform.test.flag.junit.SetFlagsRule; +import android.util.Pair; +import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; @@ -56,10 +61,13 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.Utils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowAudioManager; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settings.testutils.shadow.ShadowFragment; @@ -99,14 +107,16 @@ import java.util.concurrent.Executor; @RunWith(RobolectricTestRunner.class) @Config( shadows = { - ShadowBluetoothAdapter.class, - ShadowBluetoothUtils.class, - ShadowFragment.class, + ShadowBluetoothAdapter.class, + ShadowBluetoothUtils.class, + ShadowFragment.class, + ShadowAudioManager.class, }) public class AudioSharingDevicePreferenceControllerTest { private static final String KEY = "audio_sharing_device_list"; private static final String KEY_AUDIO_SHARING_SETTINGS = "connected_device_audio_sharing_settings"; + private static final String TEST_DEVICE_NAME = "test"; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -140,6 +150,7 @@ public class AudioSharingDevicePreferenceControllerTest { private PreferenceCategory mPreferenceGroup; private Preference mAudioSharingPreference; private FakeFeatureFactory mFeatureFactory; + private AudioManager mAudioManager; @Before public void setUp() { @@ -153,6 +164,7 @@ public class AudioSharingDevicePreferenceControllerTest { mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); mFeatureFactory = FakeFeatureFactory.setupForTest(); + mAudioManager = mContext.getSystemService(AudioManager.class); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager; mLocalBtManager = Utils.getLocalBtManager(mContext); when(mLocalBtManager.getEventManager()).thenReturn(mEventManager); @@ -571,4 +583,51 @@ public class AudioSharingDevicePreferenceControllerTest { verify(mBluetoothDeviceUpdater, never()).forceUpdate(); verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider); } + + @Test + public void testInCallState_showCallStateTitleAndSetActiveOnDeviceClick() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + mController.displayPreference(mScreen); + + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + mController.onAudioModeChanged(); + shadowOf(Looper.getMainLooper()).idle(); + + assertThat(mPreferenceGroup.getTitle().toString()) + .isEqualTo(mContext.getString(R.string.connected_device_call_device_title)); + + BluetoothDevicePreference preference = createBluetoothDevicePreference(); + mController.onDeviceClick(preference); + verify(mCachedDevice).setActive(); + } + + @Test + public void testInNormalState_showNormalStateTitleAndDoNothingOnDeviceClick() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + mController.displayPreference(mScreen); + + mAudioManager.setMode(AudioManager.MODE_NORMAL); + mController.onAudioModeChanged(); + shadowOf(Looper.getMainLooper()).idle(); + + assertThat(mPreferenceGroup.getTitle().toString()) + .isEqualTo(mContext.getString(R.string.audio_sharing_device_group_title)); + + BluetoothDevicePreference preference = createBluetoothDevicePreference(); + mController.onDeviceClick(preference); + + verify(mCachedDevice, never()).setActive(); + } + + @NonNull + private BluetoothDevicePreference createBluetoothDevicePreference() { + Drawable drawable = mock(Drawable.class); + Pair pairs = new Pair<>(drawable, TEST_DEVICE_NAME); + when(mCachedDevice.getDrawableWithDescription()).thenReturn(pairs); + return new BluetoothDevicePreference( + mContext, + mCachedDevice, + /* showDeviceWithoutNames= */ false, + BluetoothDevicePreference.SortType.TYPE_DEFAULT); + } }