diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java index 00342b14fd0..24a28dd0602 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java @@ -22,6 +22,7 @@ import android.content.Context; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settingslib.utils.ThreadUtils; @@ -78,12 +79,10 @@ class AddSourceWaitForResponseState extends AudioStreamStateHandler { ThreadUtils.postOnMainThread( () -> { if (controller.getFragment() != null) { - AudioStreamsDialogFragment.show( + showBroadcastUnavailableNoRetryDialog( controller.getFragment(), - getBroadcastUnavailableNoRetryDialog( - preference.getContext(), - AudioStreamsHelper.getBroadcastName( - metadata))); + preference.getContext(), + AudioStreamsHelper.getBroadcastName(metadata)); } }); } @@ -103,13 +102,21 @@ class AddSourceWaitForResponseState extends AudioStreamStateHandler { return AudioStreamsProgressCategoryController.AudioStreamState.ADD_SOURCE_WAIT_FOR_RESPONSE; } - private AudioStreamsDialogFragment.DialogBuilder getBroadcastUnavailableNoRetryDialog( - Context context, String broadcastName) { - return new AudioStreamsDialogFragment.DialogBuilder(context) - .setTitle(context.getString(R.string.audio_streams_dialog_stream_is_not_available)) - .setSubTitle1(broadcastName) - .setSubTitle2(context.getString(R.string.audio_streams_is_not_playing)) - .setRightButtonText(context.getString(R.string.audio_streams_dialog_close)) - .setRightButtonOnClickListener(AlertDialog::dismiss); + private void showBroadcastUnavailableNoRetryDialog( + Fragment fragment, Context context, String broadcastName) { + var broadcastUnavailableNoRetryDialog = + new AudioStreamsDialogFragment.DialogBuilder(context) + .setTitle( + context.getString( + R.string.audio_streams_dialog_stream_is_not_available)) + .setSubTitle1(broadcastName) + .setSubTitle2(context.getString(R.string.audio_streams_is_not_playing)) + .setRightButtonText(context.getString(R.string.audio_streams_dialog_close)) + .setRightButtonOnClickListener(AlertDialog::dismiss); + + AudioStreamsDialogFragment.show( + fragment, + broadcastUnavailableNoRetryDialog, + SettingsEnums.DIALOG_AUDIO_STREAM_MAIN_JOIN_FAILED_TIMEOUT); } } diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java index 3130bbcdb42..6c449a41000 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamConfirmDialog.java @@ -21,101 +21,84 @@ import static com.android.settings.connecteddevice.audiosharing.audiostreams.Aud import android.app.Activity; import android.app.Dialog; import android.app.settings.SettingsEnums; +import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothProfile; +import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.provider.Settings; +import android.text.TextUtils; import android.util.Log; import androidx.annotation.Nullable; import com.android.settings.R; import com.android.settings.bluetooth.Utils; +import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment; import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.bluetooth.BluetoothLeBroadcastMetadataExt; -import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; - -import com.google.common.base.Strings; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; public class AudioStreamConfirmDialog extends InstrumentedDialogFragment { private static final String TAG = "AudioStreamConfirmDialog"; private static final int DEFAULT_DEVICE_NAME = R.string.audio_streams_dialog_default_device; - @Nullable private LocalBluetoothManager mLocalBluetoothManager; - @Nullable private LocalBluetoothProfileManager mProfileManager; + private Context mContext; @Nullable private Activity mActivity; - @Nullable private String mBroadcastMetadataStr; @Nullable private BluetoothLeBroadcastMetadata mBroadcastMetadata; - private boolean mIsRequestValid = false; + @Nullable private BluetoothDevice mConnectedDevice; + private int mAudioStreamConfirmDialogId = SettingsEnums.PAGE_UNKNOWN; + + @Override + public void onAttach(Context context) { + mContext = context; + mActivity = getActivity(); + if (mActivity == null) { + Log.w(TAG, "onAttach() mActivity is null!"); + return; + } + Intent intent = mActivity.getIntent(); + mBroadcastMetadata = getMetadata(intent); + mConnectedDevice = getConnectedDevice(); + mAudioStreamConfirmDialogId = + getDialogId(mBroadcastMetadata != null, mConnectedDevice != null); + super.onAttach(context); + } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setShowsDialog(true); - mActivity = getActivity(); - if (mActivity == null) { - Log.w(TAG, "onCreate() mActivity is null!"); - return; - } - mLocalBluetoothManager = Utils.getLocalBluetoothManager(mActivity); - mProfileManager = - mLocalBluetoothManager == null ? null : mLocalBluetoothManager.getProfileManager(); - mBroadcastMetadataStr = mActivity.getIntent().getStringExtra(KEY_BROADCAST_METADATA); - if (Strings.isNullOrEmpty(mBroadcastMetadataStr)) { - Log.w(TAG, "onCreate() mBroadcastMetadataStr is null or empty!"); - return; - } - mBroadcastMetadata = - BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata( - mBroadcastMetadataStr); - if (mBroadcastMetadata == null) { - Log.w(TAG, "onCreate() mBroadcastMetadata is null!"); - } else { - mIsRequestValid = true; - } } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - if (!AudioSharingUtils.isFeatureEnabled()) { - return getUnsupporteDialog(); - } - if (AudioSharingUtils.isAudioSharingProfileReady(mProfileManager)) { - CachedBluetoothDevice connectedLeDevice = - AudioStreamsHelper.getCachedBluetoothDeviceInSharingOrLeConnected( - mLocalBluetoothManager) - .orElse(null); - if (connectedLeDevice == null) { - return getNoLeDeviceDialog(); - } - String deviceName = connectedLeDevice.getName(); - return mIsRequestValid ? getConfirmDialog(deviceName) : getErrorDialog(deviceName); - } - Log.d(TAG, "onCreateDialog() : profile not ready!"); - String defaultDeviceName = - mActivity != null ? mActivity.getString(DEFAULT_DEVICE_NAME) : ""; - return mIsRequestValid - ? getConfirmDialog(defaultDeviceName) - : getErrorDialog(defaultDeviceName); + return switch (mAudioStreamConfirmDialogId) { + case SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_FEATURE_UNSUPPORTED -> + getUnsupportedDialog(); + case SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_NO_LE_DEVICE -> getNoLeDeviceDialog(); + case SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_LISTEN -> getConfirmDialog(); + default -> getErrorDialog(); + }; } @Override public int getMetricsCategory() { - // TODO(chelseahao): update metrics id - return 0; + return mAudioStreamConfirmDialogId; } - private Dialog getConfirmDialog(String name) { + private Dialog getConfirmDialog() { return new AudioStreamsDialogFragment.DialogBuilder(getActivity()) .setTitle(getString(R.string.audio_streams_dialog_listen_to_audio_stream)) .setSubTitle1( mBroadcastMetadata != null ? AudioStreamsHelper.getBroadcastName(mBroadcastMetadata) : "") - .setSubTitle2(getString(R.string.audio_streams_dialog_control_volume, name)) + .setSubTitle2( + getString( + R.string.audio_streams_dialog_control_volume, + getConnectedDeviceName())) .setLeftButtonText(getString(com.android.settings.R.string.cancel)) .setLeftButtonOnClickListener( unused -> { @@ -127,6 +110,10 @@ public class AudioStreamConfirmDialog extends InstrumentedDialogFragment { .setRightButtonText(getString(R.string.audio_streams_dialog_listen)) .setRightButtonOnClickListener( unused -> { + mMetricsFeatureProvider.action( + getActivity(), + SettingsEnums + .ACTION_AUDIO_STREAM_CONFIRM_LAUNCH_MAIN_BUTTON_CLICK); launchAudioStreamsActivity(); dismiss(); if (mActivity != null) { @@ -136,7 +123,7 @@ public class AudioStreamConfirmDialog extends InstrumentedDialogFragment { .build(); } - private Dialog getUnsupporteDialog() { + private Dialog getUnsupportedDialog() { return new AudioStreamsDialogFragment.DialogBuilder(getActivity()) .setTitle(getString(R.string.audio_streams_dialog_cannot_listen)) .setSubTitle2(getString(R.string.audio_streams_dialog_unsupported_device_subtitle)) @@ -151,10 +138,13 @@ public class AudioStreamConfirmDialog extends InstrumentedDialogFragment { .build(); } - private Dialog getErrorDialog(String name) { + private Dialog getErrorDialog() { return new AudioStreamsDialogFragment.DialogBuilder(getActivity()) .setTitle(getString(R.string.audio_streams_dialog_cannot_listen)) - .setSubTitle2(getString(R.string.audio_streams_dialog_cannot_play, name)) + .setSubTitle2( + getString( + R.string.audio_streams_dialog_cannot_play, + getConnectedDeviceName())) .setRightButtonText(getString(R.string.audio_streams_dialog_close)) .setRightButtonOnClickListener( unused -> { @@ -181,11 +171,12 @@ public class AudioStreamConfirmDialog extends InstrumentedDialogFragment { .setRightButtonText(getString(R.string.audio_streams_dialog_no_le_device_button)) .setRightButtonOnClickListener( dialog -> { - if (mActivity != null) { - mActivity.startActivity( - new Intent(Settings.ACTION_BLUETOOTH_SETTINGS) - .setPackage(mActivity.getPackageName())); - } + new SubSettingLauncher(mContext) + .setDestination( + ConnectedDeviceDashboardFragment.class.getName()) + .setSourceMetricsCategory( + SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_NO_LE_DEVICE) + .launch(); dismiss(); if (mActivity != null) { mActivity.finish(); @@ -196,14 +187,60 @@ public class AudioStreamConfirmDialog extends InstrumentedDialogFragment { private void launchAudioStreamsActivity() { Bundle bundle = new Bundle(); - bundle.putString(KEY_BROADCAST_METADATA, mBroadcastMetadataStr); + bundle.putParcelable(KEY_BROADCAST_METADATA, mBroadcastMetadata); if (mActivity != null) { new SubSettingLauncher(getActivity()) .setTitleText(getString(R.string.audio_streams_activity_title)) .setDestination(AudioStreamsDashboardFragment.class.getName()) .setArguments(bundle) - .setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN) + .setSourceMetricsCategory(getMetricsCategory()) .launch(); } } + + private @Nullable BluetoothLeBroadcastMetadata getMetadata(Intent intent) { + String metadata = intent.getStringExtra(KEY_BROADCAST_METADATA); + if (metadata == null || metadata.isEmpty()) { + return null; + } + return BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata(metadata); + } + + private int getDialogId(boolean hasMetadata, boolean hasConnectedDevice) { + if (!AudioSharingUtils.isFeatureEnabled()) { + return SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_FEATURE_UNSUPPORTED; + } + if (!hasConnectedDevice) { + return SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_NO_LE_DEVICE; + } + return hasMetadata + ? SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_LISTEN + : SettingsEnums.DIALOG_AUDIO_STREAM_CONFIRM_DATA_ERROR; + } + + @Nullable + private BluetoothDevice getConnectedDevice() { + var localBluetoothManager = Utils.getLocalBluetoothManager(getActivity()); + if (localBluetoothManager == null) { + return null; + } + LocalBluetoothLeBroadcastAssistant assistant = + localBluetoothManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + if (assistant == null) { + return null; + } + var devices = + assistant.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED}); + return devices.isEmpty() ? null : devices.get(0); + } + + private String getConnectedDeviceName() { + if (mConnectedDevice != null) { + String alias = mConnectedDevice.getAlias(); + return TextUtils.isEmpty(alias) ? getString(DEFAULT_DEVICE_NAME) : alias; + } + Log.w(TAG, "getConnectedDeviceName : no connected device!"); + return getString(DEFAULT_DEVICE_NAME); + } } diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragment.java index eb99b96fc29..83b7d9a456a 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDialogFragment.java @@ -18,6 +18,7 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; import android.app.AlertDialog; import android.app.Dialog; +import android.app.settings.SettingsEnums; import android.content.Context; import android.os.Bundle; import android.util.Log; @@ -43,15 +44,16 @@ import java.util.function.Consumer; public class AudioStreamsDialogFragment extends InstrumentedDialogFragment { private static final String TAG = "AudioStreamsDialogFragment"; private final DialogBuilder mDialogBuilder; + private int mDialogId = SettingsEnums.PAGE_UNKNOWN; - AudioStreamsDialogFragment(DialogBuilder dialogBuilder) { + AudioStreamsDialogFragment(DialogBuilder dialogBuilder, int dialogId) { mDialogBuilder = dialogBuilder; + mDialogId = dialogId; } @Override public int getMetricsCategory() { - // TODO(chelseahao): update metrics id - return 0; + return mDialogId; } @Override @@ -64,14 +66,15 @@ public class AudioStreamsDialogFragment extends InstrumentedDialogFragment { * * @param host The fragment to host the dialog. * @param dialogBuilder The builder for constructing the dialog. + * @param dialogId The dialog settings enum for logging */ - public static void show(Fragment host, DialogBuilder dialogBuilder) { + public static void show(Fragment host, DialogBuilder dialogBuilder, int dialogId) { if (!host.isAdded()) { Log.w(TAG, "The host fragment is not added to the activity!"); return; } FragmentManager manager = host.getChildFragmentManager(); - (new AudioStreamsDialogFragment(dialogBuilder)).show(manager, TAG); + (new AudioStreamsDialogFragment(dialogBuilder, dialogId)).show(manager, TAG); } static void dismissAll(Fragment host) { diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java index 0777dd47703..890879e817c 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java @@ -481,7 +481,10 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro mContext, () -> { if (mFragment != null) { - AudioStreamsDialogFragment.show(mFragment, getNoLeDeviceDialog()); + AudioStreamsDialogFragment.show( + mFragment, + getNoLeDeviceDialog(), + SettingsEnums.DIALOG_AUDIO_STREAM_MAIN_NO_LE_DEVICE); } }); } diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncState.java index 4554a4de80f..55f61fdd0e2 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncState.java +++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncState.java @@ -68,13 +68,10 @@ class WaitForSyncState extends AudioStreamStateHandler { ThreadUtils.postOnMainThread( () -> { if (controller.getFragment() != null) { - AudioStreamsDialogFragment.show( + showBroadcastUnavailableDialog( controller.getFragment(), - getBroadcastUnavailableDialog( - preference.getContext(), - AudioStreamsHelper.getBroadcastName( - metadata), - controller)); + preference.getContext(), + AudioStreamsHelper.getBroadcastName(metadata)); } }); } @@ -93,24 +90,28 @@ class WaitForSyncState extends AudioStreamStateHandler { return AudioStreamsProgressCategoryController.AudioStreamState.WAIT_FOR_SYNC; } - private AudioStreamsDialogFragment.DialogBuilder getBroadcastUnavailableDialog( - Context context, - String broadcastName, - AudioStreamsProgressCategoryController controller) { - return new AudioStreamsDialogFragment.DialogBuilder(context) - .setTitle(context.getString(R.string.audio_streams_dialog_stream_is_not_available)) - .setSubTitle1(broadcastName) - .setSubTitle2(context.getString(R.string.audio_streams_is_not_playing)) - .setLeftButtonText(context.getString(R.string.audio_streams_dialog_close)) - .setLeftButtonOnClickListener(AlertDialog::dismiss) - .setRightButtonText(context.getString(R.string.audio_streams_dialog_retry)) - .setRightButtonOnClickListener( - dialog -> { - if (controller.getFragment() != null) { - launchQrCodeScanFragment(context, controller.getFragment()); - dialog.dismiss(); - } - }); + private void showBroadcastUnavailableDialog( + Fragment fragment, Context context, String broadcastName) { + var broadcastUnavailableDialog = + new AudioStreamsDialogFragment.DialogBuilder(context) + .setTitle( + context.getString( + R.string.audio_streams_dialog_stream_is_not_available)) + .setSubTitle1(broadcastName) + .setSubTitle2(context.getString(R.string.audio_streams_is_not_playing)) + .setLeftButtonText(context.getString(R.string.audio_streams_dialog_close)) + .setLeftButtonOnClickListener(AlertDialog::dismiss) + .setRightButtonText(context.getString(R.string.audio_streams_dialog_retry)) + .setRightButtonOnClickListener( + dialog -> { + launchQrCodeScanFragment(context, fragment); + dialog.dismiss(); + }); + + AudioStreamsDialogFragment.show( + fragment, + broadcastUnavailableDialog, + SettingsEnums.DIALOG_AUDIO_STREAM_MAIN_WAIT_FOR_SYNC_TIMEOUT); } private void launchQrCodeScanFragment(Context context, Fragment fragment) {